Swift runtime

Swift runtime

[TOC]

前言

我的另一篇文章關(guān)于Objective-CiOS Runtime簡介,可以參考著閱讀宫盔。

我們都知道Objective-C是一門動態(tài)語言融虽,其動態(tài)特性主要依賴于runtime。但是Swift是一門靜態(tài)語言灼芭,那么我們常常說起的Swift runtime是怎么回事呢有额?其實純Swift是沒有動態(tài)性的,Swift runtime是指Swift中的屬性或者方法在一些修飾符修飾彼绷,繼承自NSObject的時候巍佑,可以使用runtime API進(jìn)行相關(guān)的調(diào)用,下面我們就來詳細(xì)的分析一下寄悯。

1. Runtime API

本章節(jié)不是介紹Runtime API的萤衰,而是通過Runtime API獲取Swift類中的方法和屬性。

1.1 初步探索

首先我們創(chuàng)建一個macOS命令行工程猜旬,語言選擇Swift脆栋,然后在main.swift中定義一個Swift類洒擦,代碼如下:

class Teacher {
    var age: Int = 18

    func teach(){
        print("teach")
    }
}

然后編寫一個test方法椿争,在該方法中使用Runtime API去獲取上面定義的類方法和屬性列表。(注意在Swift中使用Runtime的時候是不需要import的)

func test(){
    var methodCount:UInt32 = 0
    let methodlist = class_copyMethodList(Teacher.self, &methodCount)
    for  i in 0..<numericCast(methodCount) {
        if let method = methodlist?[i]{
            let methodName = method_getName(method);
            print("方法列表:\(String(describing: methodName))")
        }else{
            print("not found method");
        }
    }
    
    var count:UInt32 = 0
    let proList = class_copyPropertyList(Teacher.self, &count)
    for  i in 0..<numericCast(count) {
        if let property = proList?[i]{
            let propertyName = property_getName(property);
            print("屬性列表:\(String(utf8String: propertyName)!)")
        }else{
            print("not found property");
        }
    }
    
    print("test run")
}

test()

運(yùn)行熟嫩,打印結(jié)果:

image

根據(jù)打印結(jié)果我們可以知道秦踪,此時并沒有打印任何方法和屬性的列表。

接下來我們修改一下我們的類:

class Teacher {
    @objc var age: Int = 18

    @objc func teach(){
        print("teach")
    }
}
image

此時我們可以看到即打印了方列表也打印了屬性列表。但是在Swift 方法(函數(shù))調(diào)度我們提到過椅邓,如果在Swift類中只是添加了@objc修飾并不能OC中被調(diào)用舍扰。如果需要在OC中調(diào)用還需要繼承自NSObject,那么我們修改代碼如下:

class Teacher: NSObject {
    var age: Int = 18

    func teach(){
        print("teach")
    }
}
image

此處只是打印了一個init方法希坚,我們再次修改類

class Teacher: NSObject {
    @objc var age: Int = 18

    @objc func teach(){
        print("teach")
    }
}

運(yùn)行边苹,打印結(jié)果:


image

此時我們可以看到我們想要的都打印了,其實為了在Swift方法中具有動態(tài)性裁僧,還可以給方法添加dynamic關(guān)鍵字進(jìn)行修飾个束。打印結(jié)果與上面是一樣的。關(guān)于方法的調(diào)度加了什么關(guān)鍵字會有不同的調(diào)度方式聊疲,具體還是去參考我的另一篇文章Swift 方法(函數(shù))調(diào)度

說了這些有什么用呢茬底?其實從最開始的純Swift類的什么都沒打印到最后打印了方法列表和屬性列表,我們正在一步一步的引入RuntimeSwift中怎么使用获洲,以及其關(guān)聯(lián)性阱表。

1.2 在objc源碼工程中調(diào)試

下面我們打開一份可編譯的objc源碼,沒有的可以去LGCooci的GitHub下載objc4_debug贡珊。由于升級了Xcode此時我使用的是objc4-881.2

新建一個SwiftTest Target最爬,語言選擇Swift,將剛才的代碼粘貼過去门岔。運(yùn)行爱致,查看打印結(jié)果與剛才的一致。

這里將代碼修改成純Swift代碼寒随,然后跟一下源碼糠悯,以獲取方法列表為例,獲取屬性也差不多妻往。首先搜索class_copyMethodList互艾,在objc-runtime-new.mm文件中,添加如下斷點讯泣。

image

注意:首先給我們的test方法中的class_copyMethodList那行代碼添加斷點纫普,待執(zhí)行到那里的時候在打開上圖所示的斷點。到上圖所示的斷點后判帮,我們查看一下cls

image

然后點擊data()跳轉(zhuǎn)進(jìn)去局嘁,在里面我們就可以看到objc_class的源碼,這里的superclass就是指向父類的指針晦墙,cache是方法調(diào)度時的緩存悦昵,bits中通過rorw存儲著方法和屬性。關(guān)于這些可以參考我的其他關(guān)于Objective-C底層原理分析的文章晌畅。iOS OC 類原理

這里我們就打印一下superclass但指,結(jié)果如下:

image

我們可以看到,在一個Swift類中,如果什么都不繼承棋凳,它的默認(rèn)基類是SwiftObject拦坠。返回class_copyMethodList函數(shù)中,我們看獲取到的方法列表剩岳。

image

我們可以看到這個methods是個二維數(shù)組贞滨,至于里面為什么都是0呢?因為我修改類的時候沒加@objc所以取不到拍棕,然后就都是0了晓铆。加上@objc就有值了。

2. SwiftObject

在上文中我們發(fā)現(xiàn)绰播,在一個什么都不繼承的Swift類中骄噪,默認(rèn)繼承的基類是SwiftObject,下面我們就去Swift源碼中搜索一下蠢箩。

SWIFT_RUNTIME_EXPORT @interface SwiftObject<NSObject> {
 @private
  Class isa;
  SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS;
}

// The members of the HeapObject header that are not shared by a
// standard Objective-C instance
#define SWIFT_HEAPOBJECT_NON_OBJC_MEMBERS       \
  InlineRefCounts refCounts

SwiftObject.h文件中我們找到了上面的代碼链蕊,我們可以看到這里是遵守了NSObject協(xié)議的。而且在Swift源碼中也有一個TargetAnyClassMetadata有著部分與OCobjc_class類似的結(jié)構(gòu)谬泌。

image

因為Swift是一門替代Objective-C的語音滔韵,所以有著與OC相似的底層也是很正常的,畢竟要慢慢過渡呵萨,兩者之間互通是必要的過程奏属。

另外在objc源碼中我們也可以看到很多Swift的身影,比如swift_class_t就是一個很典型的例子潮峦。繼承自objc_class,又有著很多Swift特有的屬性勇婴。

struct swift_class_t : objc_class {
    uint32_t flags;
    uint32_t instanceAddressOffset;
    uint32_t instanceSize;
    uint16_t instanceAlignMask;
    uint16_t reserved;

    uint32_t classSize;
    uint32_t classAddressOffset;
    void *description;
    // ...

    void *baseAddress() {
        return (void *)((uint8_t *)this - classAddressOffset);
    }
};

那么我們不禁會有一個疑問忱嘹,既然底層是能夠互通的,那么為什么在OC中使用Swift類的時候還要集成自NSObject耕渴?

其實就是通過NSObject聲明后拘悦,編譯器才能判斷當(dāng)前的類是一個與OC交互的類。

3. 總結(jié)

關(guān)注Swift Runtime就分析這么多了橱脸,其實應(yīng)用起來跟OC的差別也不大础米,下面做個簡單的總結(jié):

  1. 對于純Swift來說是沒有動態(tài)特性的,因為Swift是一門靜態(tài)語言
  2. 方法和屬性在不加任何修飾符的情況下不具備所謂的Runtime特性
  3. Swift中的方法調(diào)度主要是函數(shù)表調(diào)度V-Table
  4. 對于純Swift類添诉,我們給方法和屬性添加@objc標(biāo)識的情況下屁桑,可以通過Runtime API拿到方法和屬性列表,但是還不能在OC中調(diào)度
  5. 對于繼承自NSObject的類來說栏赴,如果想要動態(tài)的獲取當(dāng)前屬性和方法蘑斧,必須在其聲明前添加@objc關(guān)鍵字
  6. 如果需要使用方法交換需要添加dynamic標(biāo)識。如果不添加則不能通過Runtime API進(jìn)行調(diào)用
  7. swift底層源碼中有一個SwiftObject類有著與OC類似的底層結(jié)構(gòu),在objc源碼中也有一個swift_class_t結(jié)構(gòu)體竖瘾,繼承自objc_class沟突,因此swiftoc能夠有良好的交互
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捕传,隨后出現(xiàn)的幾起案子惠拭,更是在濱河造成了極大的恐慌,老刑警劉巖庸论,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件职辅,死亡現(xiàn)場離奇詭異,居然都是意外死亡葡公,警方通過查閱死者的電腦和手機(jī)罐农,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來催什,“玉大人涵亏,你說我怎么就攤上這事∑研祝” “怎么了气筋?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長旋圆。 經(jīng)常有香客問我宠默,道長,這世上最難降的妖魔是什么灵巧? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任搀矫,我火速辦了婚禮,結(jié)果婚禮上刻肄,老公的妹妹穿的比我還像新娘瓤球。我一直安慰自己,他們只是感情好敏弃,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布卦羡。 她就那樣靜靜地躺著,像睡著了一般麦到。 火紅的嫁衣襯著肌膚如雪绿饵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天瓶颠,我揣著相機(jī)與錄音拟赊,去河邊找鬼。 笑死步清,一個胖子當(dāng)著我的面吹牛要门,可吹牛的內(nèi)容都是我干的虏肾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼欢搜,長吁一口氣:“原來是場噩夢啊……” “哼封豪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起炒瘟,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤吹埠,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后疮装,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缘琅,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年廓推,在試婚紗的時候發(fā)現(xiàn)自己被綠了刷袍。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡樊展,死狀恐怖呻纹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情专缠,我是刑警寧澤雷酪,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站涝婉,受9級特大地震影響哥力,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜墩弯,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一吩跋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧渔工,春花似錦钞澳、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽策治。三九已至脓魏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間通惫,已是汗流浹背茂翔。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留履腋,地道東北人珊燎。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓惭嚣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悔政。 傳聞我的和親對象是個殘疾皇子完箩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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

  • 編譯階段 下面是編譯階段生成的類信息: 根據(jù)上面編譯器生成的數(shù)據(jù)兄淫,可以得到一些信息: class Swift類編譯...
    hexiaoxiao閱讀 1,791評論 1 6
  • 相對于Objective-C的Runtime機(jī)制,Swift的運(yùn)行時機(jī)制相對低調(diào)很多,Swift語言是用C++編寫...
    FlyElephant閱讀 11,041評論 2 14
  • Runtime 運(yùn)?這段代碼你會發(fā)現(xiàn)拳球,當(dāng)前不管是我們的?法列表還是我們的屬性列表扔涧,此次此刻都是為空的。如果將當(dāng)前的...
    Mjs閱讀 785評論 0 1
  • 轉(zhuǎn)載原文地址 Swift是蘋果2014年發(fā)布的編程開發(fā)語言,可與Objective-C共同運(yùn)行于Mac OS和iO...
    John_LS閱讀 4,222評論 2 31
  • 轉(zhuǎn)載自:移動開發(fā)前線 Swift是蘋果2014年發(fā)布的編程開發(fā)語言,可與Objective-C共同運(yùn)行于Mac O...
    MichleMin閱讀 1,015評論 0 0