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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瓜客,一起剝皮案震驚了整個濱河市适瓦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌谱仪,老刑警劉巖玻熙,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異疯攒,居然都是意外死亡嗦随,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門敬尺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枚尼,“玉大人,你說我怎么就攤上這事砂吞∈鸹校” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵呜舒,是天一觀的道長锭汛。 經(jīng)常有香客問我笨奠,道長,這世上最難降的妖魔是什么唤殴? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任般婆,我火速辦了婚禮,結(jié)果婚禮上朵逝,老公的妹妹穿的比我還像新娘蔚袍。我一直安慰自己,他們只是感情好配名,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布啤咽。 她就那樣靜靜地躺著,像睡著了一般渠脉。 火紅的嫁衣襯著肌膚如雪宇整。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天芋膘,我揣著相機與錄音鳞青,去河邊找鬼。 笑死为朋,一個胖子當著我的面吹牛臂拓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播习寸,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼胶惰,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了霞溪?” 一聲冷哼從身側(cè)響起孵滞,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸯匹,沒想到半個月后剃斧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡忽你,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年幼东,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片科雳。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡根蟹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出糟秘,到底是詐尸還是另有隱情简逮,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布尿赚,位于F島的核電站散庶,受9級特大地震影響蕉堰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜悲龟,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一屋讶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧须教,春花似錦皿渗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贬养,卻和暖如春挤土,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背误算。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工耕挨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尉桩。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像贪庙,于是被迫代替她去往敵國和親蜘犁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容