NSCoder 是 macOS/iOS 中用于 对象编码与解码(序列化 / 反序列化) 的基础类,来自 Apple 的 Foundation 框架。它是所有编码器(如 NSKeyedArchiver、NSUnarchiver、PropertyListEncoder 等)背后的核心抽象。
NSCoder 是什么?
NSCoder 是一个抽象类,定义了用于保存或读取对象数据的方法接口,常用于:
1、存档和恢复对象:NSKeyedArchiver / NSKeyedUnarchiver。
2、Storyboard 解码:init?(coder:)。
3、将对象写入 plist 文件:PropertyListEncoder 背后也用到。
4、Core Data 中转换模型:一些 NSManagedObject 也用它归档属性。
常见子类
1、NSKeyedArchiver:对象 → 二进制(写入磁盘)。
2、NSKeyedUnarchiver:二进制 → 对象(从磁盘读取)。
3、NSUnarchiver / NSArchiver:旧版 API(现在基本不用)。
常用方法
1、解码数据(从磁盘读取时用)
func decodeObject(forKey key: String) -> Any?
func decodeBool(forKey key: String) -> Bool
func decodeInt(forKey key: String) -> Int
func decodeDouble(forKey key: String) -> Double
2、编码数据(存储时用)
func encode(_ objv: Any?, forKey key: String)
func encode(_ boolv: Bool, forKey key: String)
func encode(_ intv: Int, forKey key: String)
使用场景
1、自定义类支持存档(配合 NSCoding 协议)
class Person: NSObject, NSCoding {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func encode(with coder: NSCoder) {
coder.encode(name, forKey: "name")
coder.encode(age, forKey: "age")
}
required convenience init?(coder: NSCoder) {
let name = coder.decodeObject(forKey: "name") as? String ?? ""
let age = coder.decodeInteger(forKey: "age")
self.init(name: name, age: age)
}
}
然后存档:
let person = Person(name: "Alice", age: 30)
let data = try NSKeyedArchiver.archivedData(withRootObject: person, requiringSecureCoding: false)
try data.write(to: someURL)
2、在XIB或Storyboard加载视图时的解码器
required init?(coder: NSCoder) {
super.init(coder: coder)
// 解码 UI 或其他属性
}
这就是从 storyboard 中加载控件时,Swift 利用 NSCoder 把控件还原出来的。
3、安全解码
推荐使用:
NSKeyedArchiver.archivedData(withRootObject:..., requiringSecureCoding: true)
让类实现:
class Person: NSObject, NSSecureCoding {
static var supportsSecureCoding: Bool { true }
...
}
和 Swift Codable 关系
1、基于类:NSCoding / NSCoder基于类(NSObject),Swift Codable基于类或结构体。
2、安全性:NSCoding / NSCoder需手动实现Secure Coding,Swift Codable自动实现。
3、数据格式:NSCoding / NSCoder适用于二进制plist,Swift Codable适用于JSON / plist / 自定义。
总结
当需要解码 Storyboard / XIB 中的UI控件,可以在init(coder:)中使用NSCoder。
如果存储自定义类到本地,使用NSKeyedArchiver(底层是NSCoder)。