Swift反射
所謂反射就是可以動態(tài)獲取類型、成員信息年扩,在運行時可以調(diào)用方法吭净、屬性等行為的特性。 在使用OC
開發(fā)時很少強調(diào)其反射概念理郑,因為OC的Runtime
要比其他語言中的反射強大的多蹄溉。不過在Swift
中并不提倡使用Runtime
,而是像其他語言一樣使用反射(Reflect
)您炉,即使目前Swift
中的反射功能還比較弱柒爵,只能訪問獲取類型、成員信息赚爵。
Swift
的反射機制是基于一個叫Mirror
的結(jié)構(gòu)體來實現(xiàn)的棉胀。你為具體的實例創(chuàng)建一個Mirror
對象法瑟,然后就可以通過它查詢這個實例
Mirror結(jié)構(gòu)體常用屬性:
subjectType
:對象類型
children
:反射對象的屬性集合
displayStyle
:反射對象展示類型
下面來簡單介紹下Mirror的使用:
//定義一個類來進行測試
class Person {
var name: String?
var age: Int = 0
}
//創(chuàng)建一個對象并初始化
let p = Person()
p.name = "小強"
p.age = 13
//1. 創(chuàng)建對象的反射,獲取對象類型
let mirror: Mirror = Mirror(reflecting:p)
print("獲取對象類型\(mirror.subjectType)")
// 打印出:獲取對象類型Person
//2. 獲取對象屬性名以及對應的值
for p in mirror.children {
let propertyNameString = p.label! //屬性名使用!唁奢,因為label是optional類型
let value = p.value //屬性的值
print("\(propertyNameString)的值為\(value)")
}
/* 打印:
name的值為Optional("小強")
age的值為13
*/
//3. 獲取指定索引下的屬性類型
let children = mirror.children
let p0 = children.startIndex.advancedBy(0) //獲取name屬性的位置索引
let p0Mirror = Mirror(reflecting: children[p0].value) //name的反射
print("獲取屬性name的類型為\(p0Mirror.subjectType)")
//打遇:獲取屬性name的類型為Optional
//4. 遍歷獲取對象所有動態(tài)的屬性類型
for p in mirror.children {
let propertyNameString = p.label!
let value = p.value
let vMirror = Mirror(reflecting: value) //通過值來創(chuàng)建屬性的反射
print("屬性\(propertyNameString)類型為\(vMirror.subjectType)")
}
/* 打印:
屬性name類型為Optional
屬性age類型為Int
*/
反射的應用場景現(xiàn)在還比較狹窄麻掸,因為功能還不夠完善酥夭,我提供一個比較常見的反射應用場景,那就是自定義類模型轉(zhuǎn)字典
以下就是自定義類模型轉(zhuǎn)字典實例
//自定義用戶類
class User {
var name:String = "" //姓名
var nickname:String? //昵稱
var age:Int? //年齡
var emails:[String]? //郵件地址
var tels:[Telephone]? //電話
}
//電話結(jié)構(gòu)體
struct Telephone {
var title:String //電話標題
var number:String //電話號碼
}
//自定義一個JSON協(xié)議
protocol JSON {
func toJSONModel() -> Any?
}
//擴展協(xié)議方法脊奋,實現(xiàn)一個通用的toJSONModel方法(反射實現(xiàn))
extension JSON {
//將模型數(shù)據(jù)轉(zhuǎn)成可用的字典數(shù)據(jù)采郎,Any表示任何類型,除了方法類型
func toJSONModel() -> Any? {
//根據(jù)實例創(chuàng)建反射結(jié)構(gòu)體Mirror
let mirror = Mirror(reflecting: self)
if mirror.children.count > 0 {
//創(chuàng)建一個空字典狂魔,用于后面添加鍵值對
var result: [String:Any] = [:]
//遍歷實例的所有屬性集合
for children in mirror.children {
let propertyNameString = children.label!
let value = children.value
//判斷value的類型是否遵循JSON協(xié)議,進行深度遞歸調(diào)用
if let jsonValue = value as? JSON {
result[propertyNameString] = jsonValue.toJSONModel()
}
}
return result
}
return self
}
}
//擴展可選類型淫痰,使其遵循JSON協(xié)議最楷,可選類型值為nil時,不轉(zhuǎn)化進字典中
extension Optional: JSON {
//可選類型重寫toJSONModel()方法
func toJSONModel() -> Any? {
if let x = self {
if let value = x as? JSON {
return value.toJSONModel()
}
}
return nil
}
}
//擴展兩個自定義類型待错,使其遵循JSON協(xié)議
extension User: JSON { }
extension Telephone: JSON { }
//擴展Swift的基本數(shù)據(jù)類型籽孙,使其遵循JSON協(xié)議
extension String: JSON { }
extension Int: JSON { }
extension Bool: JSON { }
extension Dictionary: JSON { }
extension Array: JSON { }
//創(chuàng)建一個User實例對象模型
let user1 = User()
user1.name = "hangge"
user1.age = 100
user1.emails = ["hangge@hangge.com","system@hangge.com"]
//添加電話
let tel1 = Telephone(title: "手機", number: "123456")
let tel2 = Telephone(title: "公司座機", number: "001-0358")
user1.tels = [tel1, tel2]
//模型轉(zhuǎn)字典
if let model = user1.toJSONModel() {
print(model)
}
/* 打印:【以下打印經(jīng)過排版火俄,正式的打印是緊湊的】
[
"tels": [
"[1]": [
"title": "公司座機",
"number": "001-0358"
],
"[0]": [
"title": "手機",
"number": "123456"
]
],
"name": "hangge",
"emails": [
"[1]": "system@hangge.com",
"[0]": "hangge@hangge.com"
],
"age": 100
]
*/