iOS學習筆記48-Swift(八)反射

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
]
*/

有什么問題請在下方評論區中提出!O(∩_∩)O哈!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容