1. Codable
在swift 4中引入codable之后,可以将Cat声明为Codable(或者至少声明为Encodable,记住Codable其实就是Decodable & Encodable),然后使用相关的encoder来进行编码。不过swift标准库中并没有直接将一个对象编码为字典的编码器,我们可以进行一些变通,先将需要处理的类型声明为Coable,然后使用JSONEncoder将其转换为JSON数据,最后再从JSON数据中拿到对应的字典,如下代码所示,
// public typealias Codable = Decodable & Encodable
struct Cat: Codable {
let name: String
let age: Int
}
let kitten = Cat.init(name: "kitten", age: 2)
let encoder = JSONEncoder()
do {
let data = try encoder.encode(kitten)
let dictionary = try JSONSerialization.jsonObject(with: data, options: [])
print(dictionary)
} catch {
print(error)
}
2. Mirror
Mirror可以让我们在运行时一窥某个类型的实例的内容,它也是swift中位数不多的与运行时特性相关的手段。Mirror的最基本的用法如下,
struct Cat {
let name: String
let age: Int
}
let kitten = Cat.init(name: "kitten", age: 2)
let mirror = Mirror.init(reflecting: kitten)
for child in mirror.children {
print("\(child.label!) - \(child.value)")
}
通过访问实例中mirror.children的每一个child,就可以得到所有的存储属性的label和value。以label为字典键,value为字典值,我们就能从任意类型构建出对应的字典。
字典中值的类型
不过逐一,这个child中的值是以Any为类型的,也就是说任意类型都可以在child.value中表达。所以还需要做一些额外的类型保证的工作,这里添加一个DictionaryValue协议,来表示字典能接受的类型,如下代码所示,
protocol DictionaryValue {
var value: Any { get }
}
extension Int: DictionaryValue {
var value: Any {
return self
}
}
extension Float: DictionaryValue {
var value: Any {
return self
}
}
extension String: DictionaryValue {
var value: Any {
return self
}
}
extension Bool: DictionaryValue {
var value: Any {
return self
}
}
进一步对DictionaryValue协议进行扩展,让满足它的其他类型通过Mirror的方式来构建字典,如下代码所示,
extension DictionaryValue {
var value: Any {
let mirror = Mirror(reflecting: self)
var result = [String: Any]()
for child in mirror.children {
// 如果无法获得正确的key,则报错
guard let key = child.label else {
fatalError("Invalid key in child:\(child)")
}
// 如果value无法转换为DictionaryValue,则报错
if let value = child.value as? DictionaryValue {
result[key] = value.value
} else {
fatalError("Invalid value in child: \(child)")
}
}
return result
}
}
struct Cat1: DictionaryValue {
let name: String
let age: Int
}
let kitten1 = Cat1.init(name: "kitten", age: 2)
print(kitten1.value)
对于潜逃自定义DictionaryValue值的其他类型,字段转换也可以正常工作,如下代码,
struct Wizard: DictionaryValue {
let name: String
let cat: Cat1
}
let wizard = Wizard.init(name: "hermione", cat: kitten1)
print(wizard.value)
字典中的嵌套数组和字典
extension Array: DictionaryValue where Element: DictionaryValue {
var value: Any { return map{ $0.value } }
}
extension Dictionary: DictionaryValue where Value: DictionaryValue {
var value: Any { return mapValues { $0.value } }
}
/*
// 适配swift 4.1之前的代码
extension Array: DictionaryValue {
var value: Any { return map { ($0 as! DictionaryValue).value } }
}
extension Dictionary: DictionaryValue {
var value: Any { return mapValues { ($0 as! DictionaryValue).value } }
}
*/
struct Gryffindor: DictionaryValue {
let wizards: [Wizard]
}
let crooks = Cat1.init(name: "Crookshanks", age: 2)
let hermione = Wizard.init(name: "hermione", cat: crooks)
let hedwig = Cat1.init(name: "hedwig", age: 3)
let harry = Wizard.init(name: "Harry", cat: hedwig)
let gryfindor = Gryffindor.init(wizards: [harry, hermione])
print(gryfindor.value)
网友评论