Encoding/Decoding 实现 Swift 中协议的对象数组 2
Encoding/Decoding an array of objects which implements a protocol in Swift 2
我有一个继承自 NSObject
的 class,我希望它与 NSCoding
兼容。但是我 运行 在编码应该实现协议的对象数组时遇到了麻烦。
protocol MyProtocol {
var myDescription: String { get }
}
class DummyClass: NSObject, NSCopying, MyProtocol {
var myDescription: String {
return "Some description"
}
func encodeWithCoder(aCoder: NSCoder) {
// does not need to do anything since myDescription is a computed property
}
override init() { super.init() }
required init?(coder aDecoder: NSCoder) { super.init() }
}
class MyClass: NSObject, NSCoding {
let myCollection: [MyProtocol]
init(myCollection: [MyProtocol]) {
self.myCollection = myCollection
super.init()
}
required convenience init?(coder aDecoder: NSCoder) {
let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol]
self.init(myCollection: collection)
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(myCollection, forKey: "collection")
}
}
对于 aCoder.encodeObject(myCollection, forKey: "collection")
我得到错误:
Cannot convert value of type '[MyProtocol]' to expected argument type 'AnyObject?'
好的,协议显然不是 class 的实例,因此它也不是 AnyObject?
,但我不知道如何解决这个问题。可能有一个我不知道的把戏?或者你在 Swift 中的 archiving/serialization 与 Objective-C 中的不同吗?
let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol]
也可能有问题,但编译器还没有抱怨…
我刚刚自己找到了解决方案:关键是将 myCollection
映射到 [AnyObject]
,反之亦然,如下所示:
class MyClass: NSObject, NSCoding {
let myCollection: [MyProtocol]
init(myCollection: [MyProtocol]) {
self.myCollection = myCollection
super.init()
}
required convenience init?(coder aDecoder: NSCoder) {
let collection1 = aDecoder.decodeObjectForKey("collection") as! [AnyObject]
let collection2: [MyProtocol] = collection1.map { [=10=] as! MyProtocol }
self.init(myCollection: collection2)
}
func encodeWithCoder(aCoder: NSCoder) {
let aCollection: [AnyObject] = myCollection.map { [=10=] as! AnyObject }
aCoder.encodeObject(aCollection, forKey: "collection")
}
}
我知道你的标题指定Swift 2,但仅供参考,对于我正在处理的类似问题,我发现在Swift 3, 您不再需要转换为 AnyObject。
以下在 Swift 3 中对我有效(使用您的示例):
class MyClass: NSObject, NSCoding {
let myCollection: [MyProtocol]
init(myCollection: [MyProtocol]) {
self.myCollection = myCollection
super.init()
}
required convenience init?(coder aDecoder: NSCoder) {
let collection = aDecoder.decodeObject(forKey: "collection") as! [MyProtocol]
self.init(myCollection: collection)
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encode(aCollection, forKey: "collection")
}
}
我有一个继承自 NSObject
的 class,我希望它与 NSCoding
兼容。但是我 运行 在编码应该实现协议的对象数组时遇到了麻烦。
protocol MyProtocol {
var myDescription: String { get }
}
class DummyClass: NSObject, NSCopying, MyProtocol {
var myDescription: String {
return "Some description"
}
func encodeWithCoder(aCoder: NSCoder) {
// does not need to do anything since myDescription is a computed property
}
override init() { super.init() }
required init?(coder aDecoder: NSCoder) { super.init() }
}
class MyClass: NSObject, NSCoding {
let myCollection: [MyProtocol]
init(myCollection: [MyProtocol]) {
self.myCollection = myCollection
super.init()
}
required convenience init?(coder aDecoder: NSCoder) {
let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol]
self.init(myCollection: collection)
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(myCollection, forKey: "collection")
}
}
对于 aCoder.encodeObject(myCollection, forKey: "collection")
我得到错误:
Cannot convert value of type '[MyProtocol]' to expected argument type 'AnyObject?'
好的,协议显然不是 class 的实例,因此它也不是 AnyObject?
,但我不知道如何解决这个问题。可能有一个我不知道的把戏?或者你在 Swift 中的 archiving/serialization 与 Objective-C 中的不同吗?
let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol]
也可能有问题,但编译器还没有抱怨…
我刚刚自己找到了解决方案:关键是将 myCollection
映射到 [AnyObject]
,反之亦然,如下所示:
class MyClass: NSObject, NSCoding {
let myCollection: [MyProtocol]
init(myCollection: [MyProtocol]) {
self.myCollection = myCollection
super.init()
}
required convenience init?(coder aDecoder: NSCoder) {
let collection1 = aDecoder.decodeObjectForKey("collection") as! [AnyObject]
let collection2: [MyProtocol] = collection1.map { [=10=] as! MyProtocol }
self.init(myCollection: collection2)
}
func encodeWithCoder(aCoder: NSCoder) {
let aCollection: [AnyObject] = myCollection.map { [=10=] as! AnyObject }
aCoder.encodeObject(aCollection, forKey: "collection")
}
}
我知道你的标题指定Swift 2,但仅供参考,对于我正在处理的类似问题,我发现在Swift 3, 您不再需要转换为 AnyObject。
以下在 Swift 3 中对我有效(使用您的示例):
class MyClass: NSObject, NSCoding {
let myCollection: [MyProtocol]
init(myCollection: [MyProtocol]) {
self.myCollection = myCollection
super.init()
}
required convenience init?(coder aDecoder: NSCoder) {
let collection = aDecoder.decodeObject(forKey: "collection") as! [MyProtocol]
self.init(myCollection: collection)
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encode(aCollection, forKey: "collection")
}
}