编码/解码在Swift 2中实现协议的对象数组

时间:2016-01-29 14:41:18

标签: swift serialization nscoding

我有一个继承自NSObject的类,我希望它符合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?'

好吧,一个协议显然不是一个类的实例,所以它不是AnyObject?但我不知道如何解决这个问题。可能有一个我不知道的伎俩?或者你在Swift中以与Objective-C相同的方式进行归档/序列化?

let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol]可能存在问题,但编译器还没有抱怨......

2 个答案:

答案 0 :(得分:1)

我自己刚刚找到了解决方案:关键是将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 { $0 as! MyProtocol }


        self.init(myCollection: collection2)
    }

    func encodeWithCoder(aCoder: NSCoder) {
        let aCollection: [AnyObject] = myCollection.map { $0 as! AnyObject }

        aCoder.encodeObject(aCollection, forKey: "collection")
    }      
}

答案 1 :(得分:0)

我知道您的标题指定了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")
    }      
}