iOS Sharing #01 | 2019-03-23

Adrenine發表於2019-03-22

目錄

1、Runtime存在的意義是什麼?

2、根元類的isa指標指向誰?

3、根元類的superClass指標指向誰?

4、函式四要素都是什麼?

5、例項方法去哪裡找?


1、Runtime存在的意義是什麼?

答:Objective-C 是一門動態語言,它會將一些工作放在程式碼執行時才處理而並非編譯時。也就是說,有很多類和成員變數在我們編譯的時是不知道的,而在執行時,我們所編寫的程式碼會轉換成完整的確定的程式碼執行。因此,只有編譯器是不夠的,我們還需要一個執行時系統(Runtime system)來處理編譯後的程式碼。 這就是 Objective-C Runtime 系統存在的意義,它是整個Objc執行框架的一塊基石。

平時編寫的OC程式碼,底層都是由他實現的,如:

[receiver message];
//底層執行時會被編譯器轉化為:
objc_msgSend(receiver, selector)
//如果其還有引數比如:
[receiver message:(id)arg...];
//底層執行時會被編譯器轉化為:
objc_msgSend(receiver, selector, arg1, arg2, ...)

複製程式碼

2、根元類的isa指標指向誰?

答: 見下一問

3、根元類的superClass指標指向誰?

答:這兩題一起回答。首先看下圖:

nsobject

先說幾個概念:
1)supercalss : 父類
2)subclass: 子類
3)isa : 概念不好說,官方文件說的也不清晰。作用是根據 isa 指標就可以找到物件所屬的類,但是isa指標在程式碼執行時並不總指向例項物件所屬的型別,所以不能依靠它來確定型別,要想確定型別還是需要用物件的 -class 方法。(PS:KVO 的實現機理就是將被觀察物件的isa指標指向一箇中間類而不是真實型別。)
4)class : 類,一個執行時類中關聯了它的父類指標、類名、成員變數、方法、快取以及附屬的協議。(一個例項物件是一個類的例項)
5)meta class :元類,Objc 類本身也是一個物件 ,類物件所屬的類就叫做元類(一個類是元類的例項)

第一列是類的例項變數,如:[Person new]或者[[Person alloc] init]出來的物件;
第二列是類本身,存放父類指標、類名、成員變數、方法、快取以及附屬的協議的資訊;
第三列是元類

  • 1)isa路線:
    • 例項物件的isa指向Class
    • Class的isa指向Meta Class
    • Meta Class的isa指向根元類Root Meta Class
    • 根元類的isa指向自己
  • 2)superclass路線:
    • 例項物件沒有superclass ;
    • 例項物件所在的類,存在superclass,類的superclass後面會指向Root Class,Root Class的super Class是nil;
    • 元類也存在superclass,元類的superclass後面會指向Root Meta Class,而Root Meta Class的superclass卻是Root Class。

所以:

  • 根元類的isa指標指向自己
  • 根元類的superclass指向root class
  • 根類的isa指向根元類
  • 根類的superclass指向nil

附舊版Class結構:

typedef struct objc_class *Class;
Class 其實是指向 objc_class 結構體的指標。objc_class 的資料結構如下:
struct objc_class {
    Class isa  OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
    Class super_class                                        OBJC2_UNAVAILABLE;
    const char *name                                         OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list *ivars                             OBJC2_UNAVAILABLE;
    struct objc_method_list **methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache *cache                                 OBJC2_UNAVAILABLE;
    struct objc_protocol_list *protocols                     OBJC2_UNAVAILABLE;
#endif
} OBJC2_UNAVAILABLE;

複製程式碼
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;
/// A pointer to an instance of a class.
typedef struct objc_object *id;

複製程式碼
  • Class是一個指向objc_class(類)結構體的指標,而id是一個指向objc_object(物件)結構體的指標。

  • objec_object(物件)中isa指標指向的類結構稱為objec_class(該物件的類),其中存放著普通成員變數與物件方法 (“-”開頭的方法)。

  • objec_class(類)中isa指標指向的類結構稱為metaclass(該類的元類),其中存放著static型別的成員變數與static型別的方法 (“+”開頭的方法)。

附圖:
舊版Class

objc-old
新版Class

objc-new


4、函式四要素都是什麼?

答:函式名,函式引數,引數型別,返回值型別(PS:ObjC一般叫方法,不叫函式)

OC method簡單介紹

typedef struct objc_method *Method;
struct objc_method {
    SEL method_name OBJC2_UNAVAILABLE;  //方法名
    char *method_types OBJC2_UNAVAILABLE;   //方法型別
    IMP method_imp OBJC2_UNAVAILABLE;   //方法實現
}
複製程式碼

objc_method 儲存了方法名,方法型別和方法實現。

方法名型別為 SEL

方法型別 method_types 是個 char 指標,儲存方法的引數型別和返回值型別 method_imp 指向了方法的實現,本質是一個函式指標 Ivar Ivar 是表示成員變數的型別。

typedef struct objc_ivar *Ivar;
struct objc_ivar {
    char *ivar_name OBJC2_UNAVAILABLE;
    char *ivar_type OBJC2_UNAVAILABLE;
    int ivar_offset OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space OBJC2_UNAVAILABLE;
#endif
}
複製程式碼

其中 ivar_offset 是基地址偏移位元組

IMP

IMP在objc.h中的定義是:

typedef id (*IMP)(id, SEL, ...);
複製程式碼

它就是一個函式指標,這是由編譯器生成的。當你發起一個 ObjC 訊息之後,最終它會執行的那段程式碼,就是由這個函式指標指定的,而 IMP 這個函式指標就指向了這個方法的實現。


5、例項方法去哪裡找?

答:其所屬的類的方法表

擴充

問:oc是如何找到需要執行哪個方法的?
答:當需要執行某個例項方法的時候(類方法類似),oc會先去該類的方法的快取列表裡面查詢,若找到了,則執行,否則,去該類的方法列表中查詢是否存在該方法,存在,執行該方法並更新方法快取列表,否則,去該父類快取以及父類方法列表查詢,直到根類,若還未找到,則啟用動態解析以及訊息轉發流程,若還是失敗,報unrecognized selector異常

詳細流程
感謝大佬提供的流程圖


聯絡方式

郵箱: adrenine@163.com

郵箱: holaux@gmail.com

郵箱: ledahapple@icloud.com

相關文章