Search code examples
swift3xcode8ios10

NSKeyedArchiver does not work in Swift 3 (Xcode 8)


I have migrated my project to Swift 3 and NSKeyedArchiver does not work. I actually have a runtime error when trying to decode object like this:

let startDayTime = aDecoder.decodeObject(forKey: Key.startDayTime) as! Int

It worked perfectly in Swift 2.2 in Xcode 7.3. Has anybody else faced such troubles?

P.S. I have this error on both Simulator and Device.


Solution

  • It appears that this only happens on the Swift 2 to Swift 3 update boundary when a NSData blob archived with a NSKeyedArchiver in Swift 2 is opened with a NSKeyedUnarchiver in Swift 3. My guess is that on Swift 2, the Bool and Int are encoded as NSNumber, but in Swift 3, they are encoded as raw Bool and Int types. I believe the following test supports this claim:

    This works in Swift 3 to unarchive a Bool encoded in Swift 2, but returns nil if the Bool was encoded in Swift 3:

    let visible = aDecoder.decodeObject(forKey: "visible") as? Bool
    

    This works in Swift 3 to unarchive a Bool encoded in Swift 3, but crashes if the Bool was encoded in Swift 2:

    let visible = aDecoder.decodeBool(forKey: "visible")
    

    My solution is:

    let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")