一般来说,Objective-C
通过 NSCoding
归档数据,Swift
采用 Codable
方式。但是并不意味着它们无法协同工作,需要一些很少的工作就可以将 NSCoding
的数据在 Codable
内部进行归档。怎么理解?
比方说, UIColor
和 UIImage
实现了 NSCoding
但是并没有实现 Codable
。
这里我们通过一个简单的 struct 举例:
struct Person {
var name: String
var favoriteColor: UIColor
}
复制代码
如何将 Person
实现 Codable
, 然后通过 JSONEncoder
进行归档?
我们将按这 4 个步骤:
- 创建
Persion
的extension
,且遵守Codable
协议 - 创建自定义的
CodingKey
,用以描述哪些数据会被保存 - 实现
init(from:)
方法,将原始数据转化为UIColor
类型 - 实现
encode(to:)
方法,将UIColor
数据转为原始数据,这样Codable
可以将其 base-64 编码
首先给 Persion 添加 extension:
extension Persion: Codable {
}
复制代码
添加后,编译是失败的,因为 UIColor
没有实现 Codable
。那我们继续第二步:添加自定义的 coding keys
。
enum CodingKeys: String, CodingKey {
case name
case favoriteColor
}
复制代码
我们需要通过声明这些 coding keys
进行手动地编码和解码。
实现解码操作:
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
// 获取到原始数据
let colorData = try container.decode(Data.self, forKey: .favoriteColor)
// 进行解码
favoriteColor = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(colorData) as? UIColor ?? UIColor.black
}
复制代码
实现编码操作:
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(name, forKey: .name)
// 转化为 原始数据
let colorData = try NSKeyedArchiver.archivedData(withRootObject: favoriteColor, requiringSecureCoding: false)
// 进行编码
try container.encode(colorData, forKey: .favoriteColor)
}
复制代码
上面的工作完成后,我们就可以愉快的玩耍了。
let taylor = Person(name: "Swift", favoriteColor: .blue)
let encoder = JSONEncoder()
do {
let encoded = try encoder.encode(taylor)
let str = String(decoding: encoded, as: UTF8.self)
print(str)
} catch {
print(error.localizedDescription)
}
复制代码