Swift 5 + iOS 13 以后的归档解档NSKeyedUnarchiver+ NSKeyedArchiver

1,045 阅读2分钟

这里主要是更新一下网上的资料

网上大多资料处理归档解档的资料都还在 swift 3 或者 4 或者更早期的 api

虽然实际开发中用得更多的是存 kv 系统 或者通过 coredata 框架存进去 sqlite 数据库, 但估计又不少新 iOSer 会在学习的过程中触碰到归档解档的问题

废话少说, 直接上代码

// model 模型中必须继承 nsobject + 遵守coding 协议+ 安全编码协议
class Model: NSObject,
NSCoding,
NSSecureCoding

循例实现协议

func encode(with coder: NSCoder) {

// 将自己的模型的属性编码 + key
// coder.encode(name, forKey: "name")
// coder.encode(age, forKey: "age")
}

required init?(coder: NSCoder) {

// 解档的时候给模型赋值
// name = coder.decodeObject(forKey: "name") as? String
// age = coder.decodeObject(forKey: "age") as? Int
}
// 给自己的对象增加一个保存方法, 封装在 model 内部, 当然也可以随便写在啥地方
func saveModel(){

let path = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!).appendingPathComponent("model.plist")

// 确认文件真的保存

print(path ?? "")

// 3. 归档保存
do{
let userData = try? NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: true)

try userData?.write(to: path!)

print("Saved")

}catch let error as NSError{

print("\(error)")
}
}
// UI 部分 自己随便整几个按钮跟 label 在 storyboard 上面然后调用下面的方法就可以了
class ViewController: UIViewController {
    
    
    @IBOutlet weak var infoLbl: UILabel!
    
    
    @IBAction func unarchBtnCli(_ sender: UIButton) {
        print("接档操作")
        
            // 获取文件路径 url
        let searchPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
        let searchPathWithFile = (searchPath as NSString).appendingPathComponent("model.plist")
        let fileUrl = URL(fileURLWithPath: searchPathWithFile)
        
        var unarchModel: Model?
        
            // 尝试从 路径上获取 data 二进制流
        do {
            let data = try Data(contentsOf: fileUrl)
                // 从二进制流中解析 Model 对象
            unarchModel = try NSKeyedUnarchiver.unarchivedObject(ofClass: Model.self, from: data)
                //                    unarchModel = try NSKeyedUnarchiver.unarchiveObject(withFile: searchPathWithFile) as! Model
                // 旧版 api 已经被废弃 是直接从 file 里面解析
        } catch let err {
            print(err.localizedDescription)
        }
        
            // 判断解析出来的 model 是否为空 并更新 ui
        if nil != unarchModel {
            print("unarch => \(unarchModel?.name) + \(unarchModel?.age)")
                // 更新 ui
            infoLbl.text = "==\(unarchModel?.name) + \(unarchModel?.age)=="
        }
    }
    
    @IBAction func archBtnClicked(_ sender: Any) {
            // 实例化对象
        var demoModel = Model()
        
            // 赋值
        demoModel.name = "啊爸爸啊吧"
        demoModel.age = 250
        
            // 保存
        demoModel.saveModel()
        print("保存操作")
    }
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
}

文档的关键点, 如果实在解决不了还是直接看文档吧!

image.png