1.数据模型:在传统的类定义基础上,加上(1)数据存储地址ArchiveURL(2)继承NSObject,遵从NSCoding协议(实现用于将数据编码的func encode(with aCoder: NSCoder),实现将归档数据恢复为类数据对象的required convenience init?(coder aDecoder: NSCoder)。) 只用遵从NSCoding协议的类才能被编码归档。
import UIKit
import os.log
class Country:NSObject,NSCoding {
//MARK:Property
let name:String
var nationalFlagImage:UIImage
var capital:String
var mainCities:[String]
//MARK:创建数据存储的url路径
//(1)使用FileManager对象,获得用户域的通用目录的url
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
//(2)创建用于存储的url路径:在DocumentsDirectory基础上,加上路径元素,相当于在DocumentsDirectory路径下,创建了一个文件 夹,用于存放数据
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("countries")
init(name:String,nationalFlagImage:UIImage,capital:String,mainCities:[String]) {
self.name = name
self.nationalFlagImage = nationalFlagImage
self.capital = capital
self.mainCities = mainCities
//这句话时初始化父类NSObject
super.init()
}
///持久化相关代码
//(1)为Country类中的所有属性设置相应的键名,类似于数据里面的属性名
struct PropertyKey {
static let name = "name"
static let nationalFlagImage = "nationalFlagImage"
static let capital = "capital"
static let mainCities = "mainCities"
}
//(2)让Country类继承 NSObject 类,并实现 NSCoding 协议
// 继承了 NSObject 类,需要在本类初始化时,完成父类的初始化
// NSCoding协议需要实现 encode 函数和 init?初始化函数
// 为每个属性绑定相应的键名,以键名编码
func encode(with aCoder: NSCoder){
aCoder.encode(name, forKey: PropertyKey.name)
aCoder.encode(nationalFlagImage, forKey: PropertyKey.nationalFlagImage)
aCoder.encode(capital, forKey: PropertyKey.capital)
aCoder.encode(mainCities, forKey: PropertyKey.mainCities)
}
// 以键名解码
required convenience init?(coder aDecoder: NSCoder){
guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {
os_log("无法完成解码", log: .default, type: .debug)
return nil
}
guard let nationalFlagImage = aDecoder.decodeObject(forKey: PropertyKey.nationalFlagImage) as? UIImage else {
os_log("无法完成解码", log: .default, type: .debug)
return nil
}
guard let capital = aDecoder.decodeObject(forKey: PropertyKey.capital) as? String else {
os_log("无法完成解码", log: .default, type: .debug)
return nil
}
guard let mainCities = aDecoder.decodeObject(forKey: PropertyKey.mainCities) as? [String] else {
os_log("无法完成解码", log: .default, type: .debug)
return nil
}
self.init(name: name, nationalFlagImage: nationalFlagImage, capital: capital, mainCities: mainCities)
}
}
2. 使用 NSKeyedArchiver.archiveRootObject(countries, toFile: Country.ArchiveURL.path)实现Country数组数据的归档存储。
使用 NSKeyedUnarchiver.unarchiveObject(withFile: Country.ArchiveURL.path) as? [Country]实现已归档数据的重新载入,解码。