在日常開發(fā)活動(dòng)中, 很多時(shí)候都需要將某個(gè)實(shí)體轉(zhuǎn)換為字典, 而轉(zhuǎn)換字典的方式有千千萬萬種, 這里介紹一種利用 Swift 的反射獲取屬性并轉(zhuǎn)換的方式.
原理就是利用 Mirror 類提供的能力將實(shí)體中所有屬性都遍歷出來, 然后將屬性名作為 key, 屬性值作為 value 存入到字典中.
首先定義一個(gè)協(xié)議, 有了協(xié)議之后可以很方便地為協(xié)議提供默認(rèn)實(shí)現(xiàn), 從而避免對(duì)每個(gè)實(shí)體類型都單獨(dú)寫轉(zhuǎn)換方法:
/// 字典轉(zhuǎn)換協(xié)議
protocol DictionaryConvertible {
/// 將實(shí)體轉(zhuǎn)換為字典.
///
/// - Returns: 實(shí)體對(duì)應(yīng)的字典
func toDictionary() -> [String: Any]
}
定義好了這個(gè)協(xié)議, 就可以給這個(gè)協(xié)議提供默認(rèn)實(shí)現(xiàn)了:
extension DictionaryConvertible {
func toDictionary() -> [String: Any] {
var dictionary = [String: Any]()
let mirrorSelf = Mirror(reflecting: self)
mirrorSelf.children.forEach({ label, value in
guard let key = label else { return }
if let array = value as? Array<DictionaryConvertible> {
dictionary[key] = array.map({ $0.toDictionary() })
} else if let convertible = value as? DictionaryConvertible {
dictionary[key] = convertible.toDictionary()
} else {
dictionary[key] = value
}
})
return dictionary
}
}
其中考慮了實(shí)體屬性是如下兩種類型的可能:
屬性是
DictionaryConvertible, 則對(duì)該屬性的值也進(jìn)行字典轉(zhuǎn)換.屬性是
DictionaryConvertible數(shù)組, 則將數(shù)組的每個(gè)元素都轉(zhuǎn)換為字典.
完整代碼如下:
protocol DictionaryConvertible {
/// 將實(shí)體轉(zhuǎn)換為字典.
///
/// - Returns: 實(shí)體對(duì)應(yīng)的字典
func toDictionary() -> [String: Any]
}
extension DictionaryConvertible {
func toDictionary() -> [String: Any] {
var dictionary = [String: Any]()
let mirrorSelf = Mirror(reflecting: self)
mirrorSelf.children.forEach({ label, value in
guard let key = label else { return }
if let array = value as? Array<DictionaryConvertible> {
dictionary[key] = array.map({ $0.toDictionary() })
} else if let convertible = value as? DictionaryConvertible {
dictionary[key] = convertible.toDictionary()
} else {
dictionary[key] = value
}
})
return dictionary
}
}
在實(shí)際使用時(shí), 假設(shè)有如下實(shí)體類型:
struct MyInnerConsParam: Encodable, DictionaryConvertible {
let info: String
let price: Double
}
struct MyConsPostParam: Encodable, DictionaryConvertible {
let name: String
let num: Int
let inner: MyInnerConsParam
}
只要讓實(shí)體遵守 DictionaryConvertible 協(xié)議即可獲取字典轉(zhuǎn)換能力:
let inner = MyInnerConsParam(info: "這個(gè)有信息", price: 33.3)
let param = MyConPostParam(name: "二狗", num: 11, inner: inner)
let dict = param.toDictionary()
print(dict)
打印結(jié)果如下:
["inner": ["info": "這個(gè)有信息", "price": 33.3], "name": "二狗", "num": 11]