在 Swift 中访问共享容器中的自定义对象
Posted
技术标签:
【中文标题】在 Swift 中访问共享容器中的自定义对象【英文标题】:Access custom object in shared container in Swift 【发布时间】:2017-05-10 21:44:13 【问题描述】:我正在制作一个自定义键盘,我想在容器应用程序中构建一个资产(特别是 trie 字典),然后在键盘扩展通过共享容器启动时访问它。为此,我将从这个相当基础的课程开始:
class Person: NSObject, NSCoding
let name: String
let age: Int
init(name: String, age: Int)
self.name = name
self.age = age
required init(coder decoder: NSCoder)
self.name = decoder.decodeObject(forKey: "name") as? String ?? ""
self.age = decoder.decodeInteger(forKey: "age")
func encode(with coder: NSCoder)
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
太好了。我已经设置了我的共享容器,并在容器应用程序的 ViewController 的 viewDidLoad 函数中加载了共享容器(一些测试变量和自定义对象):
let shared = UserDefaults(suiteName: "group.test_keyboard")
shared!.set("test", forKey:"key_string")
shared!.set(false, forKey:"key_boolean")
shared!.set(34, forKey:"key_int")
let newPerson = Person(name: "Joe", age: 10)
let encodedData = NSKeyedArchiver.archivedData(withRootObject: newPerson)
shared!.set(encodedData, forKey: "people")
为了测试它,我在 viewWillAppear 中添加了以下代码:
let shared = UserDefaults(suiteName: "group.test_keyboard")
let test_string = shared?.string(forKey: "key_string")
if(test_string != nil)
print("string-\(test_string!)")
else
print("nil")
// retrieving a value for a key
if let data = shared?.data(forKey: "people")
let test_person = NSKeyedUnarchiver.unarchiveObject(with: data) as? Person
print("-\(test_person!.name)") // Joe
let data_size = String(data.count)
print("-\(data_size)")
else
print("There is an issue")
一切正常。但是当我进入 KeyboardViewController 并尝试访问时,检索简单的字符串可以正常工作:
let shared = UserDefaults(suiteName: "group.test_keyboard")
shared?.synchronize()
let test_string = shared?.string(forKey: "key_string")
if(test_string != nil)
(textDocumentProxy as UIKeyInput).insertText(test_string!)
else
(textDocumentProxy as UIKeyInput).insertText("nil")
但是如果我尝试访问自定义对象 Person,如下所示:
if let data = shared?.data(forKey: "people")
(textDocumentProxy as UIKeyInput).insertText("found")
(textDocumentProxy as UIKeyInput).insertText(String(data.count))
let myPeople = NSKeyedUnarchiver.unarchiveObject(with: data) as? Person
我收到以下错误响应的崩溃:
2017-05-10 14:34:46.938253-0700 test_keyboard[3196:857207] viewServiceDidTerminateWithError:: 错误 域=_UIViewServiceInterfaceErrorDomain 代码=3“(空)” UserInfo=Message=服务连接中断
数据在那里,如果我在两侧进行简单的 data.count 检查,它的大小相同(269)。如果我注释掉 NSKeyedUnarchiver 行,就没有问题,所以我确定这就是问题所在。当它在容器应用程序中正常工作时,到底发生了什么导致它在键盘扩展中崩溃?
【问题讨论】:
【参考方案1】:很可能是在不同模块中运行的问题。您的应用是与扩展不同的模块,完全限定的类名包括模块名。在应用程序中类似于AppName.Person
,但在扩展程序中类似于KeyboardExt.Person
。 NSCoding
无法匹配这些,所以它很糟糕。
有几种解决方法。一种是创建一个应用程序和扩展程序都使用的框架,并将共享类放在那里。然后模块的名称将始终类似于“FrameworkName.Person”,并且一切正常。
另一种是专门告诉(取消)归档过程该类使用什么名称。然后它将写入您指定的名称并将其与适当的类匹配。在写入任何数据之前,请执行以下操作
NSKeyedArchiver.setClassName("Person", for: Person.self)
然后在读取任何数据之前,做相反的事情:
NSKeyedUnarchiver.setClass(Person.self, forClassName: "Person")
【讨论】:
这看起来很有希望 - 我会试一试! @asetniop 您通过我的网站和 Twitter 联系了我,询问我是否愿意回答这个问题。如果有帮助,请将其标记为已接受。如果没有,请描述您遇到的问题。 它做到了! (对不起,速度慢了——我妻子需要 macbook 作证)非常感谢!以上是关于在 Swift 中访问共享容器中的自定义对象的主要内容,如果未能解决你的问题,请参考以下文章
将 Alamofire 调用包装到 Swift 中的自定义对象中?
在 Swift 中将自定义 UITableViewCell 共享到多个 UITableViewController