简体   繁体   English

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

[英]Encoding/Decoding an array of objects which implements a protocol in Swift 2

I have got a class that inherits from NSObject and I want it to be NSCoding compliant. 我有一个继承自NSObject的类,我希望它与NSCoding兼容。 But I ran into trouble while encoding an array of objects which should implement a protocol. 但是我在编码应该实现协议的对象数组时遇到麻烦。

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

For aCoder.encodeObject(myCollection, forKey: "collection") I get the error: 对于aCoder.encodeObject(myCollection, forKey: "collection")我收到错误:

Cannot convert value of type '[MyProtocol]' to expected argument type 'AnyObject?'

OK, a protocol obviously is not an instance of a class and so it isn't AnyObject? 好的,协议显然不是类的实例,因此不是AnyObject? but I've no idea how to fix that. 但我不知道如何解决。 Probably there is a trick that I'm not aware? 也许有一个我不知道的把戏? Or do you do archiving/serialization differently in Swift as in Objective-C? 还是在Swift中和在Objective-C中进行归档/序列化不同?

There's probably a problem with let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol] let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol]可能存在问题let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol] let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol] , too but the compiler doesn't complain yet… let collection = aDecoder.decodeObjectForKey("collection") as! [MyProtocol]也是如此,但是编译器还没有抱怨……

I've just found the solution myself: The key is to map myCollection into [AnyObject] and vice-versa, like so: 我自己找到了解决方案:关键是将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")
    }      
}

I know your title specifies Swift 2, but just for reference, for a similar problem I was working on, I found that in Swift 3 , you don't need to convert anymore to AnyObject. 我知道您的标题指定了Swift 2,但仅供参考,对于我正在处理的类似问题,我发现在Swift 3中 ,您不再需要转换为AnyObject。

The following works for me in Swift 3 (using your example): 以下内容适用于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")
    }      
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM