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")
    }      
}