16

我已将我的项目迁移到 Swift 3 并且NSKeyedArchiver无法正常工作。尝试像这样解码对象时,我实际上遇到了运行时错误:

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

它在 Xcode 7.3 中的 Swift 2.2 中完美运行。有没有其他人遇到过这样的麻烦?

PS我在模拟器和设备上都有这个错误。

4

4 回答 4

16

似乎这只发生在 Swift 2 到 Swift 3 更新边界上,当NSKeyedArchiver在 Swift 2 中使用 a 归档的 NSData blob 在 Swift 3 中使用 a 打开时NSKeyedUnarchiver。我的猜测是,在 Swift 2 上,BoolandInt被编码为NSNumber,但在 Swift 中3、它们被编码为rawBoolInttypes。我相信以下测试支持这一说法:

这在 Swift 3 中可以解压缩Bool在 Swift 2 中编码的文件,但nil如果 Bool 是在 Swift 3 中编码的,则返回:

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

这在 Swift 3 中可以解压缩Bool在 Swift 3 中编码的文件,但如果 Bool 是在 Swift 2 中编码的,则会崩溃:

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

我的解决方案是:

let visible = aDecoder.decodeObject(forKey: "visible") as? Bool ?? aDecoder.decodeBool(forKey: "visible")
于 2016-10-14T03:56:18.570 回答
8

我通过使用解决了这个问题:

decodeInteger(forKey key: String)

代替:

decodeObject(forKey key: String)

出于某种原因,AnyObject 不会在 Swift 3 中转换为 Integer,尽管它在 Swift 2.2 中确实如此

于 2016-07-20T07:52:25.317 回答
3

这是解决方案:

class Person: NSObject, NSCoding {
    let name: String
    let age: Int
    required init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    required init(coder decoder: NSCoder) {
        self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
        self.age = decoder.decodeInteger(forKey: "age")
    }

    func encode(with coder: NSCoder) {
        coder.encode(name, forKey: "name")
        coder.encode(age, forKey: "age")
    }
}

如何使用:

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        let newPerson = Person(name: "Joe", age: 10)
        var people = [Person]()
        people.append(newPerson)
        let encodedData = NSKeyedArchiver.archivedData(withRootObject: people)
        UserDefaults.standard().set(encodedData, forKey: "people")
        if let data = UserDefaults.standard().data(forKey: "people"),
            myPeopleList = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Person] {
            myPeopleList.forEach({print( $0.name, $0.age)})  // Joe 10
        } else {
            print("There is an issue")
        }
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

参考:Swift 3 从 userDefaults 保存和检索自定义对象

于 2016-11-28T10:10:02.323 回答
1

斯威夫特 3

我采用双问号( ?? ) 方法,它只在一行中就可以发挥作用。

如果 val 不是 nil ,则将其解包并返回值。如果为 nil,则aDecoder.decodeInteger(forKey: "val")返回:

self.val = aDecoder.decodeObject(forKey: "val") as? Int ?? aDecoder.decodeInteger(forKey: "val")
于 2016-10-15T13:06:52.727 回答