NSCoder:如何编码/解码[Data]数组

huangapple go评论63阅读模式
英文:

NSCoder: how to encode/decode [Data] array

问题

我在尝试编码/解码数据数组(基本上是文件书签)时遇到了问题,使用了NSCoder协议。

这是我尝试的代码:

class ClosedFiles: NSCoder {
    static var supportsSecureCoding = true
    let bookmarks: [Data]
    init?(with coder: NSCoder) {
        if let bm = coder.decodeObject() as? [Data] {
            bookmarks = bm
        } else {
            return nil
        }
    }
    init(bookmarks: [Data]) {
        self.bookmarks = bookmarks
    }
    
    func encode(with coder: NSCoder) {
        coder.encodeRootObject(bookmarks)
    }
}

我在我的应用程序委托中对这个对象进行编码:

func application(_ app: NSApplication, willEncodeRestorableState coder: NSCoder) {
    coder.encodeRootObject(ClosedFiles(bookmarks: closedFiles))
}

这会在运行时引发错误:

> 忽略异常:此解码器只会解码采用NSSecureCoding的类。类 '_TtCC7MyApp11AppDelegate11ClosedFiles' 未采用它。

我正在遵循苹果的文档来符合NSSecureCoding,但似乎不起作用。我尝试了一些其他方法,但似乎都不起作用:coder.encode(),coder.encodeConditionalObject,以及我找到的其他任何方法。

有什么想法我在做错什么吗?

英文:

I'm having troubles encoding/decoding an array of Data (basically file bookmarks) in NSCoder protocol.

Here's what I'm trying to do:

class ClosedFiles: NSCoder {
    static var supportsSecureCoding = true
    let bookmarks: [Data]
    init?(with coder: NSCoder) {
        if let bm = coder.decodeObject() as? [Data] {
            bookmarks = bm
        } else {
            return nil
        }
    }
    init(bookmarks: [Data]) {
        self.bookmarks = bookmarks
    }
    
    func encode(with coder: NSCoder) {
        coder.encodeRootObject(bookmarks)
    }
}

I encode this object in my app delegate:

func application(_ app: NSApplication, willEncodeRestorableState coder: NSCoder) {
    coder.encodeRootObject(ClosedFiles(bookmarks: closedFiles))
}

This throws the error in runtime:

> Ignoring exception: This decoder will only decode classes that adopt
> NSSecureCoding. Class '_TtCC7MyApp11AppDelegate11ClosedFiles' does
> not adopt it.

I'm following the apple's doc to conform to NSSecure, but it doesn't seem to work.
I tried a few other method, but nothing seems working: coder.encode(), coder.encodeConditionalObject, and whatever else I found.

Any thought what I'm doing wrong?

答案1

得分: 2

您需要对您的类进行许多更改,以支持NSCoding(实际上是NSSecureCoding)。

  • 您的类必须扩展NSObject
  • 您的类需要符合NSSecureCoding
  • 您需要为init(coder:)初始化器提供正确的签名。
  • supportsSecureCoding属性需要是静态的。
  • 需要正确编写两个NSCoding方法的实现以支持安全编码。

以下是已经进行了所有更改的您的类。

class ClosedFiles: NSObject, NSSecureCoding {
    let bookmarks: [Data]

    required init?(coder: NSCoder) {
        if let bm = coder.decodeArrayOfObjects(ofClass: NSData.self, forKey: "bookmarks") as? [Data] {
            bookmarks = bm
        } else {
            return nil
        }
    }

    init(bookmarks: [Data]) {
        self.bookmarks = bookmarks
    }

    func encode(with coder: NSCoder) {
        coder.encode(bookmarks as [NSData], forKey: "bookmarks")
    }

    static var supportsSecureCoding: Bool {
        return true
    }
}

我使用以下代码在Playground中测试了这些更改:

do {
    let closed = ClosedFiles(bookmarks: [ "Hello".data(using: .utf8)!, "There".data(using: .utf8)! ])
    let data = try NSKeyedArchiver.archivedData(withRootObject: closed, requiringSecureCoding: true)
    let dupe = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [ClosedFiles.self, NSArray.self, NSData.self], from: data) as! ClosedFiles
    let str1 = String(data: dupe.bookmarks[0], encoding: .utf8)!
    print(str1)
} catch {
    print(error)
}

这将返回预期的结果。

英文:

You need a lot of changes for your class to support NSCoding (actually NSSecureCoding.

  • Your class must extend NSObject
  • Your class needs to conform to NSSecureCoding
  • You need the correct signature for the init(coder:) initializer
  • The supportsSecureCoding property needs to be static
  • The implementation of the two NSCoding methods need to be written correctly to support secure coding.

Here's your class with all of the changes.

class ClosedFiles: NSObject, NSSecureCoding {
    let bookmarks: [Data]

    required init?(coder: NSCoder) {
        if let bm = coder.decodeArrayOfObjects(ofClass: NSData.self, forKey: "bookmarks") as? [Data] {
            bookmarks = bm
        } else {
            return nil
        }
    }

    init(bookmarks: [Data]) {
        self.bookmarks = bookmarks
    }

    func encode(with coder: NSCoder) {
        coder.encode(bookmarks as [NSData], forKey: "bookmarks")
    }

    static var supportsSecureCoding: Bool {
        return true
    }
}

I tested these changes in a Playground using the following code:

do {
    let closed = ClosedFiles(bookmarks: [ "Hello".data(using: .utf8)!, "There".data(using: .utf8)! ])
    let data = try NSKeyedArchiver.archivedData(withRootObject: closed, requiringSecureCoding: true)
    let dupe = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [ClosedFiles.self, NSArray.self, NSData.self], from: data) as! ClosedFiles
    let str1 = String(data: dupe.bookmarks[0], encoding: .utf8)!
    print(str1)
} catch {
    print(error)
}

This gives back the expected results.

huangapple
  • 本文由 发表于 2023年6月16日 12:31:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76486969.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定