swift - 格式错误的 NSKeyedUnarchiver 数据

标签 swift nscoding nskeyedarchiver nscoder nskeyedunarchiver

我正在使用 ARKit 和 GameKitMatches,所以我不能使用 Codable (afaik) 因为 MCPeerIDARWorldMap 都不可编码,所以我无法使用 Codable路在先。

所以我正在使用 NSCoding 和 NSSecureCoding 但出于某种原因我总是会遇到错误:

无法读取数据,因为它的格式不正确。

...即使我真的只是创造了它。 我还尝试使用 NSKeyedUnarchiver.unarchivedObject(ofClasses: classes 但这在我的初始化中抛出了一个意外的 nil。

这是我制作的展示问题的 Playground :

class CodingData: NSObject, NSCoding, NSSecureCoding {
    static var supportsSecureCoding = true
    var dic: [String: Int]!
    var i: Int!

    func encode(with coder: NSCoder) {
        coder.encode(i, forKey: "i")
        coder.encode(dic, forKey: "dic")
    }

    required convenience init?(coder: NSCoder) {
        let anInt = coder.decodeObject(forKey: "i") as! Int
        let anDic = coder.decodeObject(forKey: "dic") as! [String: Int]
        self.init(dic: anDic, i: anInt)
    }

    init(dic: [String: Int], i: Int){
        self.dic = dic
        self.i = i
    }
}

do{
    let test = CodingData(dic: [:], i: 0)
    //let classes = [NSDictionary.self, NSNumber.self]
    let testData = try NSKeyedArchiver.archivedData(withRootObject: test, requiringSecureCoding: true)
    let emptyDic = try NSKeyedUnarchiver.unarchivedObject(ofClass: CodingData.self, from: testData)
    // Error here ^^^^^^
}catch{
    error.localizedDescription
}

顺便说一句,不确定它是否重要,但在尝试调试 init 中的 coder 时它总是说(可能只是一个错误):

error: <EXPR>:1:1: error: non-nominal type '$__lldb_context' (aka 'Self') cannot be extended
extension $__lldb_context {
^         ~~~~~~~~~~~~~~~

error: <EXPR>:19:27: error: value of type 'Self' has no member '$__lldb_wrapped_expr_28'
    $__lldb_injected_self.$__lldb_wrapped_expr_28(
    ~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~

最佳答案

您已经做出了很大的努力,但是您的代码有很多错误,我认为最简单的回答方法就是更正它:

class CodingData: NSObject, NSSecureCoding {
    static var supportsSecureCoding = true
    var dic: [String: Int]
    var i: Int

    func encode(with coder: NSCoder) {
        coder.encode(i as NSNumber, forKey: "i")
        coder.encode(dic as NSDictionary, forKey: "dic")
    }

    required init?(coder: NSCoder) {
        let anInt = coder.decodeObject(of: NSNumber.self, forKey: "i")
        let anDic = coder.decodeObject(of: NSDictionary.self, forKey: "dic")
        self.dic = anDic as! [String:Int]
        self.i = anInt as! Int
    }

    init(dic: [String: Int], i: Int){
        self.dic = dic
        self.i = i
    }
}

它现在可以工作了:

let test = CodingData(dic: [:], i: 0)
let testData = try NSKeyedArchiver.archivedData(withRootObject: test, requiringSecureCoding: true)
let emptyDic = try NSKeyedUnarchiver.unarchivedObject(ofClass: CodingData.self, from: testData)
print(emptyDic?.dic as Any, emptyDic?.i as Any) // Optional([:]) Optional(0)

所以你的四个主要错误是:

  • 不要将实例属性声明为隐式展开的 Optional (!)

  • init?(coder:) 不是便利初始化器

  • 要进行安全编码,您必须使用安全编码 (decodeObject(of:forKey:)) 对每个编码属性进行解码

  • 只有 NSSecureCoding 类型可以使用安全编码进行编码,因此 Swift 类型必须转换为它们的 Objective-C 等价物

关于swift - 格式错误的 NSKeyedUnarchiver 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58018520/

相关文章:

ios - 清除按钮未显示在 UITextField 上

swift - swift 中的 WKwebview

ios - 让 iPhone 在本地通知时振动

arrays - Swift NSCoding - 如何读取编码数组

swift - 引用其他模型的模型 - 使用 NSCoding 保存

iphone - NSKeyedUnarchiver 未按预期运行

ios - 你能在本地快速保存一组 ViewControllers (NSKeyedArchiver) 吗?

swift 错误 : 'missing return in function' ?

ios - 尝试在 Swift 3 中保存自定义对象时尝试插入非属性列表对象

objective-c - NSKeyedArchiver 保存的是什么格式?