NSCoding error messages using NSKeyedUnarchiver.unarchivedObject(ofClass:from:)

I get a code-time yellow warning message in Xcode that says:


'unarchiveObject(with:)' was deprecated in iOS 12.0: Use +unarchivedObjectOfClass:fromData:error: instead


... when I use the following code:


let oldUbiquityIdentityToken = NSKeyedUnarchiver
        .unarchiveObject(with: oldDataUbiquityIdentityToken!)


When I change to unarchivedObject(ofClass:from:) I get 2 code-time red error messages before I even fill in the arguments:


'NSCoding' cannot be used as a type conforming to protocol 'NSCoding' because 'NSCoding' has static requirements


Static method 'unarchivedObject(ofClass:from:)' requires that 'NSCoding' inherit from 'NSObject'


Here is the code afterwards before I fill in the parameters:


let oldUbiquityIdentityToken = NSKeyedUnarchiver.unarchivedObject(ofClass: NSCoding.Protocol, from: Data)


Why am I getting these error messages?

Answered by OOPer in 414743022

Thanks for showing the info about how `oldDataUbiquityIdentityToken` is made.

As you have found in the doc, the return type of `ubiquityIdentityToken` is sort of an opaque type.


You cannot use ` unarchivedObject(ofClasses:from:)` or `unarchivedObject(ofClass:from:)` for such an object,

you need to know the definite class of the object, not protocols.


In this case, you can use another method:

    do {
        let oldUbiquityIdentityToken = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(oldDataUbiquityIdentityToken!)
        //...
    } catch {
        print(error)
    }

When I change to unarchivedObject(ofClass:from:) I get 2 code-time red error message

Please show the changed code.


Why am I getting these error messages?

Because you are using the code in a wrong way. But without showing your code, it is very hard to say where to fix.

Ok. I added the code after I changed it. I didn't fill in the parameters.

Thanks for updating. Of course, no method would work if you do not pass parameters.

According to your old code, you could write something like this:

let oldUbiquityIdentityToken = NSKeyedUnarchiver.unarchivedObject(ofClass: ???, from: oldDataUbiquityIdentityToken!)

And the actual parameter passed for `ofClass` needs to be a class contained in the archived data.


I do not know the content of your archive, so I cannot write the exact answer for you.

Just for example, if the archived data contains Array, you may need to write something like this:

    do {
        let unarchivedArray = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSArray.self, from: archivedData!) as! [Any]
        //...
    } catch {
        print(error)
        //Other things needed on error
    }

If your archive contains multiple classes, you may need to use `unarchivedObject(ofClasses:from:)` instead of `unarchivedObject(ofClass:from:)`.


You may need some modifications to your archived class, but it is very hard to say something now.

Here's what code I have now:


        let defaultFileManager: FileManager = FileManager.default
        let standardUserDefaults = UserDefaults.standard
        
        let ubiquityIdentityToken = defaultFileManager.ubiquityIdentityToken
        
        let oldDataUbiquityIdentityToken = standardUserDefaults.data(forKey: UserDefaultsKeys.ubiquityIdentityToken)
        
        do {
            // Save ubiquity identity token
            let dataUbiquityIdentityToken: Data = try NSKeyedArchiver.archivedData(withRootObject: ubiquityIdentityToken!, requiringSecureCoding: false)
            standardUserDefaults.set(dataUbiquityIdentityToken, forKey: UserDefaultsKeys.ubiquityIdentityToken)
            
            let oldUbiquityIdentityToken = try NSKeyedUnarchiver.unarchivedObject(ofClass: (NSCoding & NSCopying & NSObjectProtocol).self, from: oldDataUbiquityIdentityToken!)
            
        } catch {
            
            print(error)
            
        }

Here are the red code-time errors that appear on the line below the comments in the code:


'NSCoding & NSCopying & NSObjectProtocol' cannot be used as a type conforming to protocol 'NSCoding' because 'NSCoding' has static requirements


Static method 'unarchivedObject(ofClass:from:)' requires that 'NSCoding & NSCopying & NSObjectProtocol' inherit from 'NSObject'


I get the argument I put in for the 'forClass' parameter from the declaration of FileManager.ubiquityIdentityToken in Apple's documentation, which says:


@NSCopying var ubiquityIdentityToken: (NSCoding & NSCopying & NSObjectProtocol)? { get }


What threw me off at the beginning is the fact that the errors appear before I even put in the arguments in the placeholders.

Accepted Answer

Thanks for showing the info about how `oldDataUbiquityIdentityToken` is made.

As you have found in the doc, the return type of `ubiquityIdentityToken` is sort of an opaque type.


You cannot use ` unarchivedObject(ofClasses:from:)` or `unarchivedObject(ofClass:from:)` for such an object,

you need to know the definite class of the object, not protocols.


In this case, you can use another method:

    do {
        let oldUbiquityIdentityToken = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(oldDataUbiquityIdentityToken!)
        //...
    } catch {
        print(error)
    }

Ok. Thank you very much.

NSCoding error messages using NSKeyedUnarchiver.unarchivedObject(ofClass:from:)
 
 
Q