Search code examples
iosswiftnskeyedunarchiver

How to replace NSKeyedUnarchiver.unarchiveTopLevelObjectWithData with unarchivedObject when data is a Dictionary


iOS 16.4 deprecates unarchiveTopLevelObjectWithData(_:) and should be replaced with unarchivedObject(ofClass:from:).

When you archived a Swift Dictionary like [String: Any], how do you use the newer API to unarchive it?

NSKeyedUnarchiver.unarchivedObject(ofClass: [String: Any].self, from: data) results in a build time error:

Static method 'unarchivedObject(ofClass:from:)' requires that '[String : Any]' conform to 'NSCoding'

//create the data from dictionary
let dictionary: [String: Any] = ["Text": "Hello", "Number": 1, "Array": ["Hello", "World"]]
let data = try! NSKeyedArchiver.archivedData(withRootObject: dictionary, requiringSecureCoding: true)

//and later get the dictionary from the data
let dictionary = try? NSKeyedUnarchiver.unarchivedObject(ofClass: [String: Any].self, from: data) //sorry no can do

Solution

  • Since the Swift dictionary of type [String: Any] doesn't conform to NSCoding, you need to drop back to using NSDictionary. Since you are also using secure coding, you also need to list all types that can be in the dictionary.

    You will need to use the unarchivedObject(ofClasses:from:) method so you can list all of the classes.

    let dictionary = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSDictionary.self, NSArray.self], from: data) as? NSDictionary
    

    You may also end up needing to add NSString.self and NSNumber.self to the list of classes. Keep adding the classes that appear in the error message until it works.