NSKeyedUnarchiver 数据格式错误

Posted

技术标签:

【中文标题】NSKeyedUnarchiver 数据格式错误【英文标题】:NSKeyedUnarchiver data in wrong format 【发布时间】:2020-01-20 22:21:00 【问题描述】:

我正在使用 ARKit 和 GameKitMatches,所以我不能使用 Codable (afaik),因为 MCPeerIDARWorldMap 不可编码,首先要解决这个问题。

所以我正在使用 NSCoding 和 NSSecureCoding 但由于某种原因我总是会发现错误:

The data couldn’t be read because it isn’t in the correct format.

...即使我只是创建了它。 我也尝试使用NSKeyedUnarchiver.unarchivedObject(ofClasses: classes,但这在我的初始化中抛出了一个意想不到的零。

这是我制作的一个展示问题的游乐场:

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(
    ~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~

【问题讨论】:

【参考方案1】:

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

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:) 不是 convenience 初始化器

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

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

【讨论】:

哇!这很有帮助.. 看起来我学习 NSCoding 的资源不是最好的.. 非常感谢!

以上是关于NSKeyedUnarchiver 数据格式错误的主要内容,如果未能解决你的问题,请参考以下文章

错误消息说我的数据为 NULL - NSKeyedUnArchiver - 我已按照所有步骤操作 - 仍然无法工作

NSKeyedUnarchiver unarchiveObjectWithData 返回 nil

重命名 Xcode 项目后出现 NSKeyedUnarchiver 错误

-[NSKeyedUnarchiver decodeObjectForKey:]:无法解码类的对象

NSKeyedUnarchiver - 需要尝试/捕获?

NSKeyedUnArchiver 崩溃