NSKeyedUnarchiver数据格式错误

3

我正在使用ARKit和GameKitMatches,所以我不能使用Codable(据我所知),因为MCPeerID和ARWorldMap都不是可编码的,首先要解决这个问题。

所以我使用NSCoding和NSSecureCoding,但出现了错误:

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

即使我刚刚创建了它。 我还尝试使用NSKeyedUnarchiver.unarchivedObject(ofClasses: classes,但在我的init中抛出了意外的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(
    ~~~~~~~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~
1个回答

6
您已经付出了很大的努力,但是您的代码存在很多问题,我认为最简单的答案就是纠正它:
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)

因此,你的四个主要错误是:

  • 不要将实例属性声明为隐式解包可选项(!

  • init?(coder:) 不是一个方便的初始化器

  • 为了进行安全编码,你必须使用安全编码 (decodeObject(of:forKey:)) 解码每个已编码的属性

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


哇!太有帮助了...看来我学习NSCoding的资源不是最好的...非常感谢! - thisIsTheFoxe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接