在为自定义NSView子类实现init(coder:)
的过程中,我遇到了一些我还不完全了解的NSKeyedArchiver和NSKeyedUnarchiver奇怪的行为。考虑以下示例代码:
let label = NSTextField(labelWithString: "Test")
// Encode
let data = try NSKeyedArchiver.archivedData(withRootObject: label, requiringSecureCoding: false)
// Decode
try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSTextField
这似乎可以按预期对NSTextField进行编码和解码。但是,如果我尝试使用decodeTopLevelObject()
而不是unarchiveTopLevelObjectWithData(_:)
,则结果为nil
:
// Encode
let data = try NSKeyedArchiver.archivedData(withRootObject: label, requiringSecureCoding: false)
// Decode
let decoder = try NSKeyedUnarchiver(forReadingFrom: data)
decoder.decodeTopLevelObject() as? NSTextField // nil
类似地,如果我尝试使用encodedData
而不是archivedData(withRootObject:requiringSecureCoding:)
,则结果为nil
:
// Encode
let coder = NSKeyedArchiver(requiringSecureCoding: false)
coder.encodeRootObject(label)
let data = coder.encodedData
// Decode
try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? NSTextField // nil
如果我使用encode(_:forKey:)
和decodeObject(forKey:)
,结果甚至是nil
:
// Encode
let coder = NSKeyedArchiver(requiringSecureCoding: false)
coder.encode(label, forKey: "label")
let data = coder.encodedData
// Decode
let decoder = try NSKeyedUnarchiver(forReadingFrom: data)
decoder.decodeObject(forKey: "label") as? NSTextField // nil
令我惊讶的是,上面的第一个示例似乎可以正常工作,但其他示例都没有(特别是最后一个示例)。有人可以帮我了解这里发生了什么吗?
答案 0 :(得分:0)
如果您阅读init(forReadingFrom:)的文档,则说明:
此初始化程序默认情况下启用requireSecureCoding。...
这可能是您困惑的主要根源。然后将 requiresSecureCoding 设置为false,将完成以下工作:
/* ENCODING */
let archiver = NSKeyedArchiver(requiringSecureCoding: false)
archiver.encodeRootObject(label) // same as .encode(label)
archiver.encode(label, forKey: "SOME_CUSTOM_KEY")
archiver.finishEncoding() // as per documentation
let data = archiver.encodedData
/* DECODING */
let unarchiver = try! NSKeyedUnarchiver(forReadingFrom: data)
// DON'T FORGET THIS!!
unarchiver.requiresSecureCoding = false
let firstResult = unarchiver.decodeTopLevelObject() as! NSTextField . // same as .decodeObject()
let secondResult = unarchiver.decodeObject(forKey: "SOME_CUSTOM_KEY") as! NSTextField
unarchiver.finishDecoding() // as per documentation
正确编码和解码时,只需确保您具有匹配的密钥即可。 encodeRootObject(_:)与 encode(_:)的实现方式相同,内部使用 nil 的键,因此只需调用 decodeTopLevelObject()或 decodeObject()。
另一方面, NSKeyedArchiver.archivedData(withRootObject:requiringSecureCoding:)使用密钥 NSKeyedArchiveRootObjectKey ,因此您可以通过执行以下操作从技术上进行解码:>
let value = unarchiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! NSTextField
...但是您不想这样做,因为它是一个内部实现,理论上可以更改。相反,您只需要像在工作示例中那样使用 NSKeyedArchiver.unarchiveTopLevelObjectWithData(_:)。
注意:如果您使用的是安全编码,还需要考虑其他因素,但是我认为这超出了此问题的范围。