Swift 反射

與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的使用:

  1. 獲取對象類型
  2. 獲取一個類的屬性名稱和屬性的值
        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 { }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蒸殿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸣峭,更是在濱河造成了極大的恐慌宏所,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摊溶,死亡現(xiàn)場離奇詭異楣铁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)更扁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赫冬,“玉大人浓镜,你說我怎么就攤上這事【⒀幔” “怎么了膛薛?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長补鼻。 經(jīng)常有香客問我哄啄,道長,這世上最難降的妖魔是什么风范? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任咨跌,我火速辦了婚禮,結(jié)果婚禮上硼婿,老公的妹妹穿的比我還像新娘锌半。我一直安慰自己,他們只是感情好寇漫,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布刊殉。 她就那樣靜靜地躺著殉摔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪记焊。 梳的紋絲不亂的頭發(fā)上逸月,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機(jī)與錄音遍膜,去河邊找鬼碗硬。 笑死,一個胖子當(dāng)著我的面吹牛捌归,可吹牛的內(nèi)容都是我干的肛响。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了梦湘?” 一聲冷哼從身側(cè)響起痒筒,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎淆衷,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蔫磨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了圃伶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堤如。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖窒朋,靈堂內(nèi)的尸體忽然破棺而出搀罢,到底是詐尸還是另有隱情,我是刑警寧澤侥猩,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布榔至,位于F島的核電站,受9級特大地震影響欺劳,放射性物質(zhì)發(fā)生泄漏唧取。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一划提、第九天 我趴在偏房一處隱蔽的房頂上張望枫弟。 院中可真熱鬧,春花似錦腔剂、人聲如沸媒区。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袜漩。三九已至绪爸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宙攻,已是汗流浹背奠货。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留座掘,地道東北人递惋。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像溢陪,于是被迫代替她去往敵國和親萍虽。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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

  • 本文是iOS開發(fā)技巧系列---打造強(qiáng)大的BaseModel中的第四篇形真,前面三篇文章都可以看我有主頁面里面找到杉编,這里...
    黑暗中的孤影閱讀 4,163評論 3 23
  • 李龍峰_aec0閱讀 402評論 0 5
  • 如果你向客戶推銷屋面瓦,一般我們會這樣和客戶說:你如果用市面上其他的水泥瓦咆霜,有可能會導(dǎo)致屋面漏水〉寺現(xiàn)在,把這句話變...
    小橙小橙小橙閱讀 163評論 0 0
  • 以前我喜歡貓蛾坯,喜歡狗光酣,喜歡兔子、金魚脉课、熊貓救军、蝴蝶、鸚鵡等一切好看的動物倘零,總是覺得蒼蠅缤言、蜈蚣、西瓜蟲這樣的丑蟲子很惡...
    Molly_zhang閱讀 168評論 0 0
  • 1 早上起來视事,習(xí)慣性點(diǎn)開手機(jī),一一批閱微信微博庆揩,把紅點(diǎn)點(diǎn)都給消除了俐东。 在一大片只需要執(zhí)行“點(diǎn)開——退出”的消息中,...
    醒來么么閱讀 412評論 0 1