gpt4 book ai didi

objective-c - 用户默认值从 Obj C 迁移到 Swift

转载 作者:搜寻专家 更新时间:2023-10-31 08:13:13 25 4
gpt4 key购买 nike

我正在为我的 OS X 应用开发一个更新,它最初是用 Obj-C 编写的。
更新已用 Swift

重新编写

我正面临一个奇怪的用户默认处理问题。(因为用户首选项不能在更新中更改)

所有 native 类型(如 Bool、String)用户首选项都工作正常,但符合 NSCoding 的类无法反序列化/取消归档。它给出了一个错误:

Error :[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (KSPerson) for key (NS.objects); the class may be defined in source code or a library that is not linked

我做了以下尝试,但仍然无法找出解决方案

  1. 最初我认为这是由于不同的类名(在Swift 它的 Person 而不是 KSPerson)。但是更改类名(改回KSPerson)并没有解决问题
  2. 为了让类(class)更像Objective C,我还尝试在类(class)前加上@objc

这是代码

let UD = NSUserDefaults.standardUserDefaults()

func serialize() {
// Info: personList: [KSPerson]
let encodedObject: NSData = NSKeyedArchiver.archivedDataWithRootObject(personList)
UD.setObject(encodedObject, forKey: "key1")
print("Serialization complete")
}

func deserialise() {
let encodedObject: NSData = UD.objectForKey("key1") as! NSData
let personList: [KSUrlObject] = NSKeyedUnarchiver.unarchiveObjectWithData(encodedObject) as! [KSPerson]

for person in personList {
print(person)
}

注意:
我创建了 Objective C 代码的副本,并且它完美地反序列化(由原始副本序列化的内容)。
出乎我的意料。当我在 duplicate copy 中将类 KSPerson 重命名为 JSPerson 时,它给了我与上面看到的完全相同的错误

所以有一件事很清楚。您需要具有相同的类名才能取消归档 NSCoding 兼容的 objects。但这对于 Swift

来说显然是不够的

最佳答案

Swift 类包括它们的模块名称。 Objective-C 类没有。因此,当您取消存档 Objective-C 类“KSPerson”时,Swift 会查看其所有类并找到“mygreatapp.KSPerson”并得出它们不匹配的结论。

您需要告诉解档器如何将归档名称映射到模块的类名。您可以使用 setClass(_:forClassName:) 集中执行此操作:

NSKeyedUnarchiver.setClass(KSPerson.self, forClassName: "KSPerson")

这是一个全局注册,适用于所有不覆盖它的解压器。您当然可以为同一类注册多个名称以用于取消存档。例如:

NSKeyedUnarchiver.setClass(KSPerson.self, forClassName: "KSPerson")
NSKeyedUnarchiver.setClass(KSPerson.self, forClassName: "mygreatapp.Person")
NSKeyedUnarchiver.setClass(KSPerson.self, forClassName: "TheOldPersonClassName")

当你写 Swift 文件时,默认情况下它会包含模块名称。这意味着,如果您更改模块名称(或在一个模块中存档并在另一个模块中取消存档),您将无法取消存档数据。这样做有一些好处(它可以防止意外解档为错误的类型),但在许多情况下您可能不希望这样做。如果没有,您可以通过在另一个方向注册映射来覆盖它:

NSKeyedArchiver.setClassName("KSPerson", forClass:KSPerson.self)

这只会影响注册后存档的类(class)。它不会修改现有文件。

这仍然很脆弱。 unarchiveObjectWithData: 在出现 Swift 无法捕获的问题时引发 ObjC 异常。你会因为坏数据而崩溃。您可以避免使用 -decodeObjectForKey 而不是 +unarchiveObjectWithData:

let encodedObject: NSData = UD.objectForKey("key1") as? NSData ?? NSData()
let unarchiver = NSKeyedUnarchiver(forReadingWithData: encodedObject)
let personList : [KSPerson] = unarchiver.decodeObjectForKey(NSKeyedArchiveRootObjectKey) as? [KSPerson] ?? []

如果出现问题而不是崩溃,这将返回 []。它仍然尊重全局类名注册。

关于objective-c - 用户默认值从 Obj C 迁移到 Swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34412625/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com