当前位置:  开发笔记 > IOS > 正文

用户默认从Obj C迁移到Swift

如何解决《用户默认从ObjC迁移到Swift》经验,为你挑选了1个好方法。

我正在Update为我的OS X应用程序工作,最初写在Obj-C.
更新已重写Swift


我面临一个奇怪的用户默认值处理问题.(因为更新时不得更改用户首选项)

所有本机类型(如Bool, String)用户首选项都正常工作,但符合的类NSCoding不能deserialse / Unarchive.这是一个错误:

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

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

    最初我认为这是由于不同的类名(在 Swift其中Person而不是KSPerson).但是更改类名(返回KSPerson)并没有解决问题

    为了使类Objective C更像我也试过在类前面加上@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)
    }

注:
我创建了一个duplicate copyObjective C代码,并deserialised完美(什么是由原件连载).
出乎我的意料.当我将类重命名KSPersonJSPersonin时duplicate copy,给出了与上面完全相同的错误

所以有一件事是清楚的.您需要具有与Unarchive NSCoding兼容的相同类名objects.但这显然是不够的Swift



1> Rob Napier..:

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

您需要告诉unarchiver如何将存档名称映射到模块的类名.你可以集中使用setClass(_:forClassName:):

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

这是一个全局注册,适用于所有未覆盖它的unarchiver.您当然可以为同一个类注册多个名称以进行取消归档.例如:

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)

这仅影响注册后归档的类.它不会修改现有档案.

这仍然非常脆弱.unarchiveObjectWithData:当它有问题时会引发一个ObjC异常,而Swift无法捕获它.你会在糟糕的数据上崩溃.你可以避免使用-decodeObjectForKey而不是+unarchiveObjectWithData:

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

这将返回[]如果有一个问题,而不是崩溃.它仍然尊重全球类名注册.

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有