NSCoder编码解码[Data]数组报错,未适配NSSecureCoding求助
在使用NSCoder协议对[Data]数组(本质为文件书签)进行编码/解码时遇到问题,以下是我的实现代码:
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) } }
在AppDelegate中对该对象进行编码:
func application(_ app: NSApplication, willEncodeRestorableState coder: NSCoder) { coder.encodeRootObject(ClosedFiles(bookmarks: closedFiles)) }
运行时抛出如下错误:
Ignoring exception: This decoder will only decode classes that adopt NSSecureCoding. Class '_TtCC7MyApp11AppDelegate11ClosedFiles' does not adopt it.
我按照Apple官方文档适配NSSecureCoding,但似乎不起作用,尝试了coder.encode()、coder.encodeConditionalObject等其他编码方法也无效,请问我哪里出错了?
你的代码存在几个关键错误,导致无法正确适配NSSecureCoding:
类的继承与协议实现错误
你让ClosedFiles继承了NSCoder,但实际上需要继承NSObject并遵守NSSecureCoding协议。NSCoder是编码解码的工具类,不是需要编码的对象应该继承的父类。初始化方法签名错误
实现NSSecureCoding的解码方法必须是init?(coder: NSCoder),而不是init?(with coder: NSCoder),签名不匹配会导致系统无法识别你实现了安全解码逻辑。编码解码方法不符合安全规范
编码时应该使用encode(_:forKey:)而不是encodeRootObject(_:),后者是旧的非安全编码方式,不支持安全校验;解码时必须用带类型校验的decodeObject(of:forKey:),不能用无参数的decodeObject(),这是安全编码的核心要求。supportsSecureCoding未被正确识别
虽然你声明了static var supportsSecureCoding = true,但由于前面的错误,系统并没有正确识别你的类支持安全编码。
修正后的代码
ClosedFiles类实现
import Foundation class ClosedFiles: NSObject, NSSecureCoding { static var supportsSecureCoding: Bool = true let bookmarks: [Data] // 自定义初始化方法 init(bookmarks: [Data]) { self.bookmarks = bookmarks super.init() } // 解码方法(必须匹配init?(coder:)签名) required init?(coder: NSCoder) { // 安全解码:指定数组和元素类型,对应Objective-C中的NSArray<NSData*> guard let bookmarks = coder.decodeObject(of: [NSArray.self, NSData.self], forKey: "bookmarks") as? [Data] else { return nil } self.bookmarks = bookmarks super.init() } // 编码方法 func encode(with coder: NSCoder) { // 使用带key的编码方法,和解码时的key对应 coder.encode(bookmarks, forKey: "bookmarks") } }
AppDelegate中的编码调用
func application(_ app: NSApplication, willEncodeRestorableState coder: NSCoder) { // 用encode(_:forKey:)替代encodeRootObject(_:) coder.encode(ClosedFiles(bookmarks: closedFiles), forKey: "closedFiles") }
额外说明
- 解码时
decodeObject(of:forKey:)的类型参数需要同时传入数组类型NSArray.self和元素类型NSData.self,因为Swift的[Data]在Objective-C层对应NSArray<NSData *>。 - 编码和解码必须使用相同的key,确保数据能正确映射。
- 确认
closedFiles确实是[Data]类型,避免类型不匹配导致解码失败。
内容的提问来源于stack exchange,提问作者Soid

