首页 > 解决方案 > NSKeyedArchiver 无法归档对象

问题描述

我有一个从磁盘读取的 JSON 文件

这是文件的结构:

[
{
    "name": "3X",
    "priority": 33
},
{
    "name": "4X",
    "priority": 32
}
]

我正在将其解码为一个名为Test

class TestClass: NSObject, Codable {

    enum CodingKeys: String, CodingKey {
        case name, priority
    }

    let name:String
    let priority:Int

    var optional:String? = nil
    var problem:String = "eli"

    init(name:String, priority:Int, optional:String? = nil, problem:String) {
        self.name = name
        self.priority = priority
        self.optional = optional
        self.problem = problem
        super.init()
    }

}

这是我用来解码文件的代码

    if let path = Bundle.main.path(forResource: "test", ofType: "json") {
        do {
            let jsonData = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
            let testObjects = try JSONDecoder().decode([TestClass].self, from: jsonData)
            let data = try! NSKeyedArchiver.archivedData(withRootObject: testObjects, requiringSecureCoding: false)
            UserDefaults.standard.set(data, forKey: "test_objects")
        } catch {
            // error in parsing json
        }
    }

解码后,我尝试将数组保存到磁盘中,我将其转换为 NSData 以进行保存,但是NSKeyedArchiver.archivedData失败并出现以下错误:

{NSDebugDescription=Caught exception during archival: -[BugTesting.TestClass encodeWithCoder:]: unrecognized selector sent to instance 0x600002119ac0

对我来说,这看起来很奇怪,因为我遵守Codable.

任何帮助,将不胜感激。

标签: swiftcodablenskeyedarchiver

解决方案


如果您想对此进行编码,我可能会建议PropertyListEncoder. 那么你就不需要引入与以下相关的NSObject(也不是NSCoding/ NSSecureCodingcruft)NSKeyedArchiver

class TestClass: Codable {
    enum CodingKeys: String, CodingKey {
        case name, priority
    }

    let name: String
    let priority: Int

    var optional: String?
    var problem: String?

    init(name: String, priority: Int, optional: String? = nil, problem: String? = nil) {
        self.name = name
        self.priority = priority
        self.optional = optional
        self.problem = problem
    }
}

然后编码:

let data = try PropertyListEncoder().encode(test)

并解码:

let test2 = try PropertyListDecoder().decode(TestClass.self, from: data)

我不确定你为什么不编码optionalproblem. 我可能也倾向于对这些进行编码,除非出于某种原因您想在编码/解码过程中丢失该数据。如果您希望对所有属性进行编码,则可以消除CodingKeys

class TestClass: Codable {
    let name: String
    let priority: Int

    var optional: String?
    var problem: String?

    init(name: String, priority: Int, optional: String? = nil, problem: String? = nil) {
        self.name = name
        self.priority = priority
        self.optional = optional
        self.problem = problem
    }
}

推荐阅读