英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论