與iOS Runtime不一樣,Swift的反射用了另一套API,實(shí)現(xiàn)機(jī)制也完全不一樣
1. iOS Runtime
- 其實(shí)基于Objc的Runtime是iOS開發(fā)的黑魔法鸟蟹,比如神奇的Method Swizzle可以交換任何iOS的系統(tǒng)方法, 再比如消息轉(zhuǎn)發(fā)機(jī)制泣洞,又如class_copyIvarList等方法,可以動態(tài)獲取一個類裡面所有的方法和屬性, 以及動態(tài)給一個類新增屬性和方法.
- Objc的Runtime是如此的強(qiáng)大秀仲,再加上KVC和KVO這兩個利器融痛,可以實(shí)現(xiàn)很多你根本就想不到的功能,給iOS開發(fā)帶來極大的便捷神僵。
2. Apple推出全新的Swift語言后雁刷,單純的Swift型別不再兼容Objc的Runtime,
Swift作為一門靜態(tài)語言保礼,所有資料的型別都是在編譯時就確定好了的沛励,但是Apple為了讓Swift相容Objc,讓Swift也使用了Runtime炮障。這顯然會拖累Swift的執(zhí)行效率目派,和Apple所宣稱Swift具有超越Objective-C的效能的觀點(diǎn)完全不符。而Swift在將來是會慢慢替代 Objective-C的成為iOS或者OSX開發(fā)的主流語言胁赢,所以為了效能企蹭,我們應(yīng)該盡量使用原生的Swift,避免讓Runtime進(jìn)行Swift型別->Objc型別的隱式轉(zhuǎn)換智末。
Swift目前只有有限的反射功能谅摄,完全不能和Objc的Runtime相比。
什么是反射
反射是一種計算機(jī)處理方式系馆。是程式可以訪問送漠、檢測和修改它本身狀態(tài)或行為的一種能力。
上面的話來自百度百科它呀。使用反射有什么用螺男,看一些iOS Runtime的文章應(yīng)該會很明白。下面再列舉一下
- 動態(tài)地建立物件和屬性纵穿,
- 動態(tài)地獲取一個類裡面所有的屬性下隧,方法。
- 獲取它的父類谓媒,或者是實(shí)現(xiàn)了什么樣的介面(協(xié)議)
- 獲取這些類和屬性的訪問限制(Public 或者 Private)
- 動態(tài)地獲取執(zhí)行中物件的屬性值淆院,同時也能給它賦值(KVC)
- 動態(tài)呼叫例項方法或者類方法
- 動態(tài)的給類新增方法或者屬性,還可以交換方法(只限于Objective-C)
上面的一系列功能的細(xì)節(jié)和計算機(jī)語言的不同而不同句惯。對于Objective-C來說土辩,位于中的一系列方法就是完成這些功能的支救,嚴(yán)格來說Runtime并不是反射。而Swift真正擁有了反射功能拷淘,但是功能非常弱各墨,目前只能訪問和檢測它本身,還不能修改启涯。
Swift的反射
Swift的反射機(jī)制是基于一個叫Mirror的Stuct來實(shí)現(xiàn)的贬堵。具體的操作方式為:首先建立一個你想要反射的類的例項,再傳給Mirror的構(gòu)造器來例項化一個Mirror物件结洼,最后使用這個Mirror來獲取你想要的東西黎做。
Mirror結(jié)構(gòu)體常用屬性:
subjectType:對象類型
children:反射對象的屬性集合
displayStyle:反射對象展示類型
下面來簡單介紹下Mirror的使用:
- 獲取對象類型
- 獲取一個類的屬性名稱和屬性的值
let p = Person()
p.name = "劉偉湘"
p.age = 22
let mirror:Mirror = Mirror(reflecting: p)
/*
* 1. 獲取對象類型
*/
print("獲取對象類型:\(mirror.subjectType)")
//打印結(jié)果: 獲取對象類型:Person
/*
* 2. 獲取對象的所有屬性名稱和屬性值
*/
for property in mirror.children {
let propertyNameStr = property.label! // 屬性名使用!,因?yàn)閘abel是optional類型
let propertyValue = property.value // 屬性的值
print("\(propertyNameStr)的值為:\(propertyValue)")
//打印結(jié)果: name的值為:Optional("劉偉湘") age的值為:22
}
swfit反射的應(yīng)用場景現(xiàn)在還比較狹窄,因?yàn)楣δ苓€不夠完善松忍,比較常見的反射應(yīng)用場景就是自定義類模型轉(zhuǎn)字典
class NewViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "new"
self.view.backgroundColor = .white
// 創(chuàng)建一個User實(shí)例對象模型
let user1 = User()
user1.name = "劉偉湘"
user1.age = 100
user1.emails = ["506299396.qq.com","111111111111.qq.com"]
let tel1 = Telephone(title: "手機(jī)", number: "18711112222")
let tel2 = Telephone(title: "公司座機(jī)", number: "2800034")
user1.tels = [tel1, tel2]
// 模型轉(zhuǎn)字典
if let model = user1.toJSONModel() {
print(model)
}
/*
*打印結(jié)果
["age": 100, "tels": ["item0": ["number": "18711112222", "title": "手機(jī)"], "item1": ["number": "2800034", "title": "公司座機(jī)"]], "emails": ["item0": "506299396.qq.com", "item1": "111111111111.qq.com"], "name": "劉偉湘"]
*
*/
}
}
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 // 電話標(biāo)題
var number:String // 電話號碼
}
// 自定義一個JSON協(xié)議
protocol Sam_JSON {
func toJSONModel() -> Any?
}
// 擴(kuò)展協(xié)議方法,實(shí)現(xiàn)一個通用的toJSONModel方法(反射實(shí)現(xiàn))
extension Sam_JSON {
// 將模型數(shù)據(jù)轉(zhuǎn)成可用的字典數(shù)據(jù),Any表示任何類型,除了方法類型
func toJSONModel() -> Any? {
// 根據(jù)實(shí)例創(chuàng)建反射結(jié)構(gòu)體Mirror
let mirror = Mirror(reflecting: self)
if mirror.children.count > 0 {
// 創(chuàng)建一個空字典,用于后面添加鍵值對
var result: [String:Any] = [:]
for (idx, children) in mirror.children.enumerated() {
let propertyNameString = children.label ?? "item\(idx)"
let value = children.value
// 判斷value的類型是否遵循JSON協(xié)議,進(jìn)行深度遞歸調(diào)用
if let jsonValue = value as? Sam_JSON {
result[propertyNameString] = jsonValue.toJSONModel()
}
}
return result
}
return self
}
}
// 擴(kuò)展可選類型,使其遵循JSON協(xié)議,可選類型值為nil時,不轉(zhuǎn)化進(jìn)字典中
extension Optional: Sam_JSON {
func toJSONModel() -> Any? {
if let x = self {
if let value = x as? Sam_JSON {
return value.toJSONModel()
}
}
return nil
}
}
// 擴(kuò)展兩個自定義類型,使其遵循JSON協(xié)議
extension User: Sam_JSON { }
extension Telephone: Sam_JSON { }
// 擴(kuò)展Swift的基本數(shù)據(jù)類型,使其遵循JSON協(xié)議
extension String: Sam_JSON { }
extension Int: Sam_JSON { }
extension Bool: Sam_JSON { }
extension Dictionary: Sam_JSON { }
extension Array: Sam_JSON { }