ioscore-datacocoapodsnscodingnscoder

NSKeyedUnarchiver decodeObjectForKey crash after importing as a framework


Before pulling out MyClass into a framework, I could save instances of MyClass into Core Data just fine.

Here's the implementation of MyClass:

open class MyClass: NSObject, NSCoding {
  required public init?(coder aDecoder: NSCoder) {
        super.init()
        stuffs = aDecoder.decodeObject(forKey: "stuff") as? [Stuff] ?? []
    }

    open func encode(with aCoder: NSCoder) {
        aCoder.encode(stuffs, forKey: "stuffs")
    }
}

After pulling MyClass out into a framework with CocoaPods, I'm starting to get these crashes:

CoreData: error: exception handling request: <NSSQLFetchRequestContext: 0x1c019d4d0> , *** -[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (MyClass) for key (NS.objects); the class may be defined in source code or a library that is not linked with userInfo of {
    "__NSCoderInternalErrorCode" = 4864;
}

Any idea why?...


Solution

  • By moving this class into a framework you've changed it's full name. Before that would have been something like MyApp.MyClass but now it's MyFramework.MyClass. Keyed archiving doesn't know they're the same, which is what caused your problem. Deleting and reinstalling got you past the problem because there was no longer any old data to decode.

    You can tell the unarchive process how to resolve the conflict by using setClass(:forClassName:), so that you control class/name matching. You'd do something like

    NSKeyedUnarchiver.setClass(MyClass.self, forClassName: "MyApp.MyClass")
    

    That'll fix decoding. To keep round trip encoding/decoding working you probably need to do the same thing for archiving, something like

    NSKeyedArchiver.setClassName("MyApp.MyClass", for: MyClass.self)