Core data Array and Conforming to NSSecureCoding

Hello,

Ive been getting an error trying to store this type of array in my core data [CNLabeledValue<CNPhoneNumber>]
Code Block
[general] 'NSKeyedUnarchiveFromData' should not be used to for un-archiving and will be removed in a future release

There are lost of posts on this error but I can't get mine to work with an array of phone numbers stored in core data. Please help if you can.

I copied this Apple Project nearly exactly https://developer.apple.com/documentation/coredata/handling_different_data_types_in_core_data
except where they have tintColor as the transformable attribute in their .xcdatamodel file, I have put phoneNumbers and the type transformable, the same as the Apple project and the transformer ColorToDataTransformer I made a copy of theirs but changed the occurrences of UIColor to [CNLabeledValue<CNPhoneNumber>]

It didn't work.

Here is the PhoneNumbersToDataTransformer I made
Code Block
/*
See LICENSE folder for this sample’s licensing information.
Abstract:
A tranformer class that transforms NSData to UIColor and vice versa.
*/
import UIKit
import Contacts
class PhoneNumbersToDataTransformer: NSSecureUnarchiveFromDataTransformer {
override class func allowsReverseTransformation() -> Bool {
return true
}
override class func transformedValueClass() -> AnyClass {
return CNLabeledValue<CNPhoneNumber>.self
}
override class var allowedTopLevelClasses: [AnyClass] {
return [CNLabeledValue<CNPhoneNumber>.self]
}
override func transformedValue(_ value: Any?) -> Any? {
guard let data = value as? Data else {
fatalError("Wrong data type: value must be a Data object; received \(type(of: value))")
}
return super.transformedValue(data)
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let phone = value as? CNLabeledValue<CNPhoneNumber> else {
fatalError("Wrong data type. Received \(type(of: value))")
}
return super.reverseTransformedValue(phone)
}
}
extension NSValueTransformerName {
static let phoneNumbersToDataTransformer = NSValueTransformerName(rawValue: "PhoneNumbersToDataTransformer")
}

I tried changing allowedTopLevelClasses to
Code Block
override class var allowedTopLevelClasses: [AnyClass] {
return [CNLabeledValue<CNPhoneNumber>.self,NSArray.self]
}

and a few other iterations of the same code. Ive been changing things for age trying to get it to work.

The error is always something like this:

[/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Contacts.framework]\"\n)}'.\"
UserInfo={NSDebugDescription=value for key '_value' was of unexpected
class 'CNPhoneNumber (0x1ca088050)
[/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Contacts.framework]'.
Allowed classes are '{(\n \"NSArray (0x1c9d1ab28)
[/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/CoreFoundation.framework]\",\n
\"CNLabeledValue (0x1ca082010)
[/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Contacts.framework]\"\n)}'.}";
} FETCH error

[1]: https://developer.apple.com/documentation/coredata/handling_different_data_types_in_core_data

Answered by OOPer in 663846022
Sorry, not tested, but I would write something like this, if I want to store [CNLabeledValue<CNPhoneNumber>] (Array<CNLabeledValue<CNPhoneNumber>>):
Code Block
class PhoneNumbersToDataTransformer: NSSecureUnarchiveFromDataTransformer {
override class func allowsReverseTransformation() -> Bool {
return true
}
override class func transformedValueClass() -> AnyClass {
return NSArray.self //<-
}
override class var allowedTopLevelClasses: [AnyClass] {
return [CNLabeledValue<CNPhoneNumber>.self, NSArray.self, CNPhoneNumber.self] //<-
}
override func transformedValue(_ value: Any?) -> Any? {
guard let data = value as? Data else {
fatalError("Wrong data type: value must be a Data object; received \(type(of: value))")
}
return super.transformedValue(data)
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let phone = value as? [CNLabeledValue<CNPhoneNumber>] else {
fatalError("Wrong data type. Received \(type(of: value))")
}
return super.reverseTransformedValue(phone)
}
}

(In transformable attribute, the Custom Class needs to be a descendant of NSObject, in your case, it would be NSArray.)

Can you try and tell us what you get?
Accepted Answer
Sorry, not tested, but I would write something like this, if I want to store [CNLabeledValue<CNPhoneNumber>] (Array<CNLabeledValue<CNPhoneNumber>>):
Code Block
class PhoneNumbersToDataTransformer: NSSecureUnarchiveFromDataTransformer {
override class func allowsReverseTransformation() -> Bool {
return true
}
override class func transformedValueClass() -> AnyClass {
return NSArray.self //<-
}
override class var allowedTopLevelClasses: [AnyClass] {
return [CNLabeledValue<CNPhoneNumber>.self, NSArray.self, CNPhoneNumber.self] //<-
}
override func transformedValue(_ value: Any?) -> Any? {
guard let data = value as? Data else {
fatalError("Wrong data type: value must be a Data object; received \(type(of: value))")
}
return super.transformedValue(data)
}
override func reverseTransformedValue(_ value: Any?) -> Any? {
guard let phone = value as? [CNLabeledValue<CNPhoneNumber>] else {
fatalError("Wrong data type. Received \(type(of: value))")
}
return super.reverseTransformedValue(phone)
}
}

(In transformable attribute, the Custom Class needs to be a descendant of NSObject, in your case, it would be NSArray.)

Can you try and tell us what you get?
Hi,

Thank you for the Swift reply. The example you provided proceeded with no error, which is a good thing and the phone numbers were stored and accessed, its working I think. Thank you. I changed the transformable type in the Core data to NSArray and allowedTopLevelClasses to return [CNLabeledValue<CNPhoneNumber>.self, NSArray.self, CNPhoneNumber.self] //<- as you suggested and it worked. So thank you again. I am going to try now to do the same with CNLabeledValue<NSString> and a postal address, that should be similar.

Thank you! I really appreciated your help.
Core data Array and Conforming to NSSecureCoding
 
 
Q