一、Swift反射
所謂反射就是可以動態獲取類型、成員信息,在運行時可以調用方法、屬性等行為的特性。 在使用OC
開發時很少強調其反射概念,因為OC的Runtime
要比其他語言中的反射強大的多。不過在Swift
中並不提倡使用Runtime
,而是像其他語言一樣使用反射(Reflect
),即使目前Swift
中的反射功能還比較弱,只能訪問獲取類型、成員信息。
Swift
的反射機制是基於一個叫Mirror
的結構體來實現的。你為具體的實例創建一個Mirror
對象,然后就可以通過它查詢這個實例
Mirror結構體常用屬性:
subjectType
:對象類型children
:反射對象的屬性集合displayStyle
:反射對象展示類型
下面來簡單介紹下Mirror的使用:
//定義一個類來進行測試 class Person { var name: String? var age: Int = 0 } //創建一個對象並初始化 let p = Person() p.name = "小強" p.age = 13 //1. 創建對象的反射,獲取對象類型 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. 遍歷獲取對象所有動態的屬性類型 for p in mirror.children { let propertyNameString = p.label! let value = p.value let vMirror = Mirror(reflecting: value) //通過值來創建屬性的反射 print("屬性\(propertyNameString)類型為\(vMirror.subjectType)") } /* 打印: 屬性name類型為Optional 屬性age類型為Int */
反射的應用場景現在還比較狹窄,因為功能還不夠完善,我提供一個比較常見的反射應用場景,那就是自定義類模型轉字典
以下就是自定義類模型轉字典實例
//自定義用戶類 class User { var name:String = "" //姓名 var nickname:String? //昵稱 var age:Int? //年齡 var emails:[String]? //郵件地址 var tels:[Telephone]? //電話 } //電話結構體 struct Telephone { var title:String //電話標題 var number:String //電話號碼 } //自定義一個JSON協議 protocol JSON { func toJSONModel() -> Any? } //擴展協議方法,實現一個通用的toJSONModel方法(反射實現) extension JSON { //將模型數據轉成可用的字典數據,Any表示任何類型,除了方法類型 func toJSONModel() -> Any? { //根據實例創建反射結構體Mirror let mirror = Mirror(reflecting: self) if mirror.children.count > 0 { //創建一個空字典,用於后面添加鍵值對 var result: [String:Any] = [:] //遍歷實例的所有屬性集合 for children in mirror.children { let propertyNameString = children.label! let value = children.value //判斷value的類型是否遵循JSON協議,進行深度遞歸調用 if let jsonValue = value as? JSON { result[propertyNameString] = jsonValue.toJSONModel() } } return result } return self } } //擴展可選類型,使其遵循JSON協議,可選類型值為nil時,不轉化進字典中 extension Optional: JSON { //可選類型重寫toJSONModel()方法 func toJSONModel() -> Any? { if let x = self { if let value = x as? JSON { return value.toJSONModel() } } return nil } } //擴展兩個自定義類型,使其遵循JSON協議 extension User: JSON { } extension Telephone: JSON { } //擴展Swift的基本數據類型,使其遵循JSON協議 extension String: JSON { } extension Int: JSON { } extension Bool: JSON { } extension Dictionary: JSON { } extension Array: JSON { } //創建一個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] //模型轉字典 if let model = user1.toJSONModel() { print(model) } /* 打印:【以下打印經過排版,正式的打印是緊湊的】 [ "tels": [ "[1]": [ "title": "公司座機", "number": "001-0358" ], "[0]": [ "title": "手機", "number": "123456" ] ], "name": "hangge", "emails": [ "[1]": "system@hangge.com", "[0]": "hangge@hangge.com" ], "age": 100 ] */