如何在新版本上转换 NSKeyedArchiver 对象

Posted

技术标签:

【中文标题】如何在新版本上转换 NSKeyedArchiver 对象【英文标题】:How to convert NSKeyedArchiver objects over new versions 【发布时间】:2016-07-17 20:55:51 【问题描述】:

我刚刚在应用商店发布了一个应用,我的一位顾客告诉我,我应该使用 NSKeyedArchiver 将之前存储为整数的数据类型更改为 Double。

很容易更改应用程序的数据模型,但是当我在测试设备上重新加载应用程序时,NSKeyedUnarchiver 显然不想将 Integer 解码为 Double 并引发 NSInvalidUnarchiveOperation 异常。

我想知道其他 ios 开发人员将如何处理这种情况。我不想删除所有用户以前保存的数据,但这是我看到的唯一解决方案。

我的代码发布在下面。我已经注释掉了一些我尝试无济于事的解决方案

    required convenience init?(coder aDecoder: NSCoder)

       func decodeDoubles(coder aDecoder: NSCoder) throws-> (Double, Double)
           print("Getting in here")
           /* These are stored as Integers in previous version */
           let myEarned =  aDecoder.decodeDoubleForKey(PropertyKey.earnedKey)
           let myTotal = aDecoder.decodeDoubleForKey(PropertyKey.totalKey)

           /* App Crashes here - exception not caught */
           print("After decode attempt")
           return (myEarned, myTotal)
       

       let myID = aDecoder.decodeIntegerForKey(PropertyKey.idKey)
       let myName = aDecoder.decodeObjectForKey(PropertyKey.nameKey) as! String
       let myWeight = aDecoder.decodeIntegerForKey(PropertyKey.weightKey)
           /* Throws exception */
           //let myEarned =  aDecoder.decodeDoubleForKey(PropertyKey.earnedKey) 
           //let myTotal = try! aDecoder.decodeDoubleForKey(PropertyKey.totalKey)


       var myEarned: Double = 0
       var myTotal: Double = 0

       do 
          (myEarned, myTotal) = try decodeDoubles(coder: aDecoder)
        catch 
           print("Exception caught - \(error)")
           myEarned = Double(aDecoder.decodeIntegerForKey(PropertyKey.earnedKey))
           myTotal = Double(aDecoder.decodeIntegerForKey(PropertyKey.totalKey))
    

       self.init(id: myID, name: myName, weight: myWeight, earned: myEarned, total: myTotal)
   

【问题讨论】:

【参考方案1】:

您可能需要创建一个函数来升级存档,当应用程序加载时,将密钥作为整数读取,并将其写回为双精度,然后您的应用程序的其余部分可以读取和写入它通常是双倍的。您将需要一个新密钥来标记您已完成升级,这样您就不会再这样做了,也不要为新用户这样做。

【讨论】:

我会这样做的。 这是个好主意!我想到了这一点,但不确定我可以在哪里存储标志以避免在尝试将整数解码为双精度时遇到相同的问题。我想我可能会尝试将值保存到 NSUserDefaults 或将标志值添加到 NSKeyedArchiver。有什么建议吗? 将标志保存到 NSUserDefaults 可能更容易。也只是在函数中有一个 try/catch ,这样如果它不能读取整数,它将假定它是一个新用户并标记标志,所以它不会再尝试一次(或者值不存在并且不需要无论如何都要升级) 您也可以在存档中存储文档格式的版本号,并根据读取的版本号运行迁移代码。

以上是关于如何在新版本上转换 NSKeyedArchiver 对象的主要内容,如果未能解决你的问题,请参考以下文章

CoreData 可转换:自定义转换器永远不会被调用 - 使用 NSKeyedArchiver

使用 NSKeyedArchiver 解码然后编码未知类?

ios NSKeyedArchiver 释放 = 错误访问

NSKeyedArchiver.unarchiveObject Swift 3 iOS 10

NSData 从 NSKeyedArchiver 到 NSString

NSKeyedArchiver archivedDataWithRootObject: