NSUserDefaults和序列化数据

时间:2016-12-15 20:51:35

标签: xcode swift3 nsuserdefaults nscoding

我的应用程序中的数据持久性方法存在问题。决定将NSUserDefaults与NSCoding兼容的数据模型一起使用,由于我们的应用程序的规模,我不同意这一点。

我看到的问题是数据模型发生变化时,任何反序列化的尝试都会导致崩溃。必须卸载并重新安装该应用才能重新序列化。

方案

  1. 用户安装应用
  2. 用户做的事。
  3. 开发人员决定应将属性添加到其中一个序列化对象并推送更新。
  4. 用户安装更新。
  5. App go' kaboom'。
  6. 这种情况正在发生,因为数据已使用与现在尝试反序列化的模型不同的模型进行序列化。

    示例

    class Contact: NSCoding {
        var name
        var address
        var userId
    }
    ... // NSCoding compliance happens next. This object gets serialized.
    

    有人认为联系人需要更多东西:

    class Contact: NSCoding {
        var name
        var address
        var userId
        var phoneNumber
        var emailAddress
    }
    

    尝试对Contact对象进行反序列化,即使编码和解码的NSCoding合规性已更新为加载和反序列化,也会导致

    致命错误:在解包可选值时意外发现nil

    Stack Trace

    CoreDataManager.unarchiveUser

    unarchiveObject

    Worker.init

    NSCoding

    所以,我的问题是,在运行具有不同架构的应用程序的更新版本时,我们怎么可能避免发生这种崩溃?

1 个答案:

答案 0 :(得分:4)

你崩溃是因为,

  1. 您正在尝试decodeObject(forKey:)关于不存在的密钥(因为在对象编码时它不存在于类中)。此方法返回nil
  2. 您正在使用!强制解包#1的结果。
  3. 根据经验,如果您的Swift代码在包含!的行上崩溃,则!导致崩溃的可能性大约为95%。如果错误消息提到展开可选项,那么这是100%的可能性。

    decodeObject(forKey:)方法的文档说明它可能会返回nil。在您的情况下,如果您从该类的先前版本升级并且您正在解码刚刚添加的密钥,则可以确保这种情况发生。

    您的代码需要认识到新属性可能没有值。最简单的解决方法是将as!替换为as?。然后,您将获得新属性的nil值。对于非可选属性,您可以在最后添加?? "default value"之类的内容。

    在尝试解码密钥之前,您还可以使用containsValue(forKey:)方法检查值是否存在。