init?(coder:) 与 init(coder:) 的可选性。如果没有怎么办?

The optionality of init?(coder:) vs init(coder:). What to do if nil?

NSCoding 需要 init(coder:),但也有此方法的可选版本 init?(coder:)

如果这个returns nil到底应该怎么办?这甚至是个问题吗?

假设您正在使用 init(coder:) 初始化大型对象层次结构,每个对象的子对象本身使用 init?(coder:) 进行初始化。如果其中一个对象是 nil,应用程序不会崩溃吗?父对象不期望一个 nil 子对象。

它甚至对 "init nil" 意味着什么?

  class Parent: NSCoding {

       var children: [Child]

       required init?(coder aDecoder: NSCoder) {
          guard let children = aDecoder.decodeObject(forKey: "children") as? [Child] else { return nil }
          self.children = children
       }

  }

  class Child: NSCoding {
        var name: String

        required init?(coder aDecoder: NSCoder) {
            guard let name = aDecoder.decodeObject(forKey: "name") as? String else { return nil }
            self.name = name
        }

  }

一个策略是简单地 return 一个新实例,而不是简单地 returning nil。数据会丢失,但应用程序会 运行.

你最好不要return nil.

作为我在 Xcode 8.3.2 (8E2002) 中的测试,return nilinit(coder:) 中导致 NSKeyedUnarchiver.unarchiveObject 崩溃或 return意想不到的结果。

准备一个 class 编码错误的数据类型 "test2":

class MyClass: NSObject, NSCoding {
    var x: String

    init(_ x: String) {
        self.x = x
    }

    required init?(coder aDecoder: NSCoder) {
        guard let x = aDecoder.decodeObject(forKey: "x") as? String else {
            return nil
        }
        self.x = x
    }

    func encode(with aCoder: NSCoder) {
        if x == "test2" {
            aCoder.encode(Int(4), forKey: "x")
        } else {
            aCoder.encode(x, forKey: "x")
        }
    }
}

TestCaseA: 归档包含上述内容的字典 MyClass,然后取消归档。

结果:在 NSKeyedUnarchiver.unarchiveObject.

上崩溃
    let encodedData = NSKeyedArchiver.archivedData(withRootObject: [
        "k1":MyClass("test1"),
        "k2":MyClass("test2"),
        "k3":"normal things"
        ])
    UserDefaults.standard.set(encodedData, forKey: "xx")


    if let data = UserDefaults.standard.data(forKey: "xx"),
        let _data = NSKeyedUnarchiver.unarchiveObject(with: data) {
        if let dict = _data as? [String:Any] {
            debugPrint(dict.count)
        }
    }

TestCaseB: 归档一个包含上述MyClass的数组,然后取消归档。

结果: return 一个空数组(但预期是一个包含 1 个元素的数组)

    let encodedData = NSKeyedArchiver.archivedData(withRootObject: [
        MyClass("test1"),
        MyClass("test2")
        ])
    UserDefaults.standard.set(encodedData, forKey: "xx")


    if let data = UserDefaults.standard.data(forKey: "xx"),
        let _data = NSKeyedUnarchiver.unarchiveObject(with: data) {
        if let dict = _data as? [Any] {
            debugPrint(dict.count)
        }
    }