How do I store FileManager.ubiquityIdentityToken?

I need any kind of help I can get on this question and am open to any solutions or workarounds.

When I archive FileManager.ubiquityIdentityToken with NSKeyedArchiver.archivedData(withRootObject:requiringSecureCoding:), what should I set the second parameter to in order to be able to unarchive later, and how do I unarchive the Data object using unarchivedObject(ofClass:from:) or any other method of NSKeyedUnarchiver?

My code currently uses the deprecated method of archivedData(withRootObject:), which gives me a code time warning saying:

'archivedData(withRootObject:)' was deprecated in iOS 12.0: Use +archivedDataWithRootObject:requiringSecureCoding:error: instead

I'm getting code time error messages in red for the argument to archivedData(withRootObject:requiringSecureCoding:) which is declared as type Any. I tried different arguments. The one I this should work is (NSCoding & NSCopying & NSObject).Type, which generates two error messages:

Static method 'unarchivedObject(ofClass:from:)' requires that '(NSObject & NSCoding & NSCopying).Type' inherit from 'NSObject' Type '(NSObject & NSCoding & NSCopying).Type' cannot conform to 'NSCoding'

Setting the argument to (NSCoding & NSCopying & NSObject) generates the error message:

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

I haven't been able to discover what that means that 'NSCoding' has static

I get the idea to use (NSCoding & NSCopying & NSObject) because when run code:

print("type of FileManager.default.ubiquityIdentityToken: \(type(of: FileManager.default.ubiquityIdentityToken))")

the debug window shows

type of FileManager.default.ubiquityIdentityToken: Optional<NSCoding & NSCopying & NSObject>

but when I run the following code

print("type of FileManager.default.ubiquityIdentityToken: \(type(of: FileManager.default.ubiquityIdentityToken!))")

I get the following in the debug window

type of FileManager.default.ubiquityIdentityToken: _NSInlineData

I read on stackoverflow that "_NSInlineData" is not made available to us by Apple.

I'm open to doing this any other way, not necessarily with NSKeyedArchiver or NSKeyedUnarchiver, including using unsafe pointers if necessary.

In one of Apple's documentation or sample Xcode projects, I found code to check the login status of a user on iOS when an app logs on by checking FileManager.ubiquityIdentityToken and to check the current status with the previous status by checking the ubiquityIdentityToken that was saved in UserDefaults. Is there a better way of doing this?

I was dealing with this same issue in some older Objective-C code I was trying to update. After lots of different attempts I found the following solution (Swift version):

if let token = FileManager.default.ubiquityIdentityToken {
    do {
        let data = try NSKeyedArchiver.archivedData(withRootObject: token, requiringSecureCoding: true)

        if let newToken = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSData.self, from: data) {
            print("We got the token")
            if newToken.isEqual(token) {
                print("tokens match")
            } else {
                print("tokens do not match")
            }
        }
    } catch {
        print("oops: ", error)
    }
}

This works and it compiles cleanly. But I'm worried that passing in NSData.self could possibly fail in some future implementation if Apple changes how the token is encoded.

I discussed this with the Foundation team and, yeah, this is definitely our bad. We really want folks to adopt secure coding but you can’t do that in this case because secure coding requires that you have a concrete type. I’d appreciate you filing a bug about this, and then posting the bug number here so that I can make sure it lands in the right place.

In the meantime, I recommend that you work around this by casting to NSData:

guard let token = FileManager.default.ubiquityIdentityToken else {
    // … handle the no token case …
}
guard let tokenData = token as? NSData else {
    // … this should never happen …
}
… encode and decode that …

This should be safe because we don’t expect to change the underlying data type of the token (doing that would, for example, break RickMaddy’s code). Your bug report will help us track a proper fix for this (which may be to change the type of the property itself, or perhaps to add a new property, or perhaps something else entirely; predicting The Future™ is hard).

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I've reported essentially the same issue, IIUC, with NSFileVersion.persistentIdentifier.

FB10666727

How do I store FileManager.ubiquityIdentityToken?
 
 
Q