NSKeyedUnarchiver unarchivedObject: value for key ‘NS.objects’ was of unexpected class

  Kiến thức lập trình

I’m attempting to use NSKeyedArchiver in a ValueTransformer for SwiftData / Core Data.

I’m getting an error using NSKeyedUnarchiver.unarchivedObject(ofClass: on an NSArray filled with NSMeasurements:

func testEncode() throws {
  //let original: NSArray = ["Strings", "work", "fine"]
    let original: NSArray = [NSMeasurement(doubleValue: 42, unit: UnitMass.grams)]
    let data = try NSKeyedArchiver.archivedData(withRootObject: original, requiringSecureCoding: true)
    let nsArray = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSArray.self, from: data)
    XCTAssertEqual(original, nsArray)
}
    

“Error Domain=NSCocoaErrorDomain Code=4864 “value for key ‘NS.objects’ was of unexpected class ‘NSMeasurement’

Allowed classes are:
{(
“‘NSArray'”
)}

Answers on a similar question point to using NSCoder and its methods decodeArrayOfObjects(ofClass:forKey:) or decodeArrayOfObjects(ofClasses:forKey:).

However, I want to know why this does not work on the NSKeyedArchiver static method.

Is there any way to decode the array properly using the NSKeyedArchiver static unarchivedObject(ofClass: rather than the NSCoder instance methods?

You need to use NSKeyedUnarchiver unarchivedObject(ofClasses:from:) instead, even for a one-object-type array.

Use ofClasses: plural rather than ofClass: singular.

Pass the type of the collection itself plus the object type(s) inside the array.

func testEncode() throws {
    let original: NSArray = [NSMeasurement(doubleValue: 42, unit: UnitMass.grams)]
    let data = try NSKeyedArchiver.archivedData(withRootObject: original, requiringSecureCoding: true)
   
    // Using only `NSArray.self` does not work
  //let nsArray = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSArray.self, from: data)
    
    // Use [NSArray.self, NSMeasurement.self] instead
    let nsArrayAny: Any? = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSArray.self, NSMeasurement.self], from: data)
    let nsArray = nsArrayAny as! NSArray
    
    XCTAssertEqual(original, nsArray)
}

You need to pass both the collection type and the object types it contains. Omitting the array type results in the error

Error Domain=NSCocoaErrorDomain Code=4864 “value for key ‘root’ was of unexpected class ‘NSArray’ Allowed classes are: {( ‘NSMeasurement’ )}

LEAVE A COMMENT