NSCoding
这种方式是OC中就有的,比较老的方式,并且使用限制是只能是calss,然后实现NSCoding,对于struct是不能使用的。
internal func encode(with aCoder: NSCoder) {
var count :UInt32 = 0
if let ivar = class_copyIvarList(self.classForCoder, &count) {
for i in 0..<Int(count) {
let iv = ivar[i]
//获取成员变量的名称 -> c语言字符串
if let cName = ivar_getName(iv) {
//转换成String字符串
guard let strName = String(cString: cName, encoding: String.Encoding.utf8) else{
//继续下一次遍历
continue
}
//利用kvc 取值
let value = self.value(forKey: strName)
aCoder.encode(value, forKey: strName)
}
}
// 释放c 语言对象
free(ivar)
}
}
internal required init?(coder aDecoder: NSCoder) {
super.init()
var count :UInt32 = 0
if let ivar = class_copyIvarList(self.classForCoder, &count) {
for i in 0..<Int(count) {
let iv = ivar[i]
//获取成员变量的名称 -》 c语言字符串
if let cName = ivar_getName(iv) {
//转换成String字符串
guard let strName = String(cString: cName, encoding: String.Encoding.utf8) else{
//继续下一次遍历
continue
}
//进行解档取值
let value = aDecoder.decodeObject(forKey: strName)
//利用kvc给属性赋值
setValue(value, forKeyPath: strName)
}
}
// 释放c 语言对象
free(ivar)
}
}
利用运行时设置好属性,这样又多了一层限制,必须继承NSObject,因为运行时只有继承NSObject才会具备。如果不介意手动一行一行设置属性,那大可不继承NSObject。
static func saveCustomObject(customObject object: NSCoding, key: String) {
let encodedObject = NSKeyedArchiver.archivedData(withRootObject: object)
self.userDefaults.set(encodedObject, forKey: key)
self.userDefaults.synchronize()
}
static func removeCustomObject(key: String) {
self.userDefaults.removeObject(forKey: key)
}
static func getCustomObject(forKey key: String) -> Any? {
if let decodedObject = self.userDefaults.object(forKey: key), let data = decodedObject as? Data {
let object = NSKeyedUnarchiver.unarchiveObject(with: data)
return object
}
return nil
}
这样就把class归档,解档做好了,对于struct的归档必须使用取巧的方式参考这里或者这里面,NSCoding只适用于class,系统并没有提供专门的针对struct的解归档的协议.
Swift4.0后Codable
Swift4.0后解归档就变得容易多了Codable,这个协议对于class或是struct都适用,并且使用起来很简单方便。
class ClassA: Codable {
private var message : String? = "message"
private var nu : String? = "nu"
private var condition : String? = "condition"
var com : String? = "com"
var status : String? = "status"
var state : String? = "state"
var data : [ClassB]? = []
}
struct ClassB: Codable{
var time : String? = "time"
var ftime : String? = "ftime"
var context : String? = "context"
var location : String? = "location"
}
定义class和struct,只要声明实现Codable协议,不需要做额外的其他操作,比如不需要手动添加设置解归档的key等等。系统都会帮你搞定。不过需要注意的是Codable并不支持继承方式的子类解归档,也就是如果ClassC继承ClassA,如果对ClassC解归档时不会成功的,也就是说Codable不能够被继承使用,所以只能在子类实现Codable,父类不去实现Codable。
let a = ClassA()
let b = ClassB()
a.data = [b]
//归档
let encoder = JSONEncoder()
if let data = try? encoder.encode(a) {
print(String(data: data, encoding: .utf8)!)
UserDefaults.standard.set(data, forKey: "piaojin")
}
let object = UserDefaults.standard.object(forKey: "piaojin")
//解档
let decoder = JSONDecoder()
if let data = object as? Data {
let objectA = try? decoder.decode(ClassA.self, from: data)
print("\(String(describing: objectA))")
}
这样就搞定了,关于Codable的详细介绍可以参考这里和这里。