NSCoding和Codable可以共存吗?

时间:2018-06-07 16:57:04

标签: swift swift4 nscoding codable

在测试新Codable如何与NSCoding进行交互时,我已经将使用包含Codable结构的Class的NSCoding放在一起进行游乐场测试。白衣

struct Unward: Codable {
    var id: Int
    var job: String
}

class Akward: NSObject, NSCoding {

    var name: String
    var more: Unward

    init(name: String, more: Unward) {
        self.name = name
        self.more = more
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(more, forKey: "more")
    }

    required init?(coder aDecoder: NSCoder) {
        name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
        more = aDecoder.decodeObject(forKey: "more") as? Unward ?? Unward(id: -1, job: "unk")
        super.init()
    }
}

var upone = Unward(id: 12, job: "testing")
var adone = Akward(name: "Adrian", more: upone)

上述内容已被Playground接受,并且不会产生任何编译器错误。

但是,如果我尝试保存adone,那么:

let encodeit = NSKeyedArchiver.archivedData(withRootObject: adone)

游乐场迅速崩溃并出现错误:

  

错误:执行被中断,原因:EXC_BAD_INSTRUCTION(代码= EXC_I386_INVOP,子代码= 0x0)。

为什么呢? 有没有办法让NSCoding类包含一个Codable结构?

1 个答案:

答案 0 :(得分:2)

您获得的实际错误是:

  

- [_ SwiftValue encodeWithCoder:]:无法识别的选择器发送到实例

这是来自这条线:

aCoder.encode(more, forKey: "more")

问题的原因是moreUnward类型)不符合NSCoding。但是Swift struct无法符合NSCoding。除了符合Unward之外,您还需要将NSObject更改为扩展NSCoding的类。这些都不会影响符合Codable的能力。

这是您更新的课程:

class Unward: NSObject, Codable, NSCoding {
    var id: Int
    var job: String

    init(id: Int, job: String) {
        self.id = id
        self.job = job
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(id, forKey: "id")
        aCoder.encode(job, forKey: "job")
    }

    required init?(coder aDecoder: NSCoder) {
        id = aDecoder.decodeInteger(forKey: "id")
        job = aDecoder.decodeObject(forKey: "job") as? String ?? ""
    }
}

class Akward: NSObject, Codable, NSCoding {
    var name: String
    var more: Unward

    init(name: String, more: Unward) {
        self.name = name
        self.more = more
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(name, forKey: "name")
        aCoder.encode(more, forKey: "more")
    }

    required init?(coder aDecoder: NSCoder) {
        name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
        more = aDecoder.decodeObject(forKey: "more") as? Unward ?? Unward(id: -1, job: "unk")
    }
}

您的测试值:

var upone = Unward(id: 12, job: "testing")
var adone = Akward(name: "Adrian", more: upone)

您现在可以归档和取消归档:

let encodeit = NSKeyedArchiver.archivedData(withRootObject: adone)
let redone = NSKeyedUnarchiver.unarchiveObject(with: encodeit) as! Akward

你可以编码和解码:

let enc = try! JSONEncoder().encode(adone)
let dec = try! JSONDecoder().decode(Akward.self, from: enc)