天天看點

知識總結Objective-C Runtime 運作時(1)

c語言不是動态語言,函數的調用在編譯時候已經确定,編譯完成後按照順序執行即可。OC作為動态語言主要是因為Runtime庫的支援,由于Runtime庫的作用使得c語言具有了動态語言的特性,runtime保持在程式運作時建立,修改類,對象和方法,OC的函數調用通過runtime進行消息的轉發。

Object-C類

typedef struct objc_class *Class;

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;//父類
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;//類名
    long version                                             OBJC2_UNAVAILABLE;//類的版本資訊
    long info                                                OBJC2_UNAVAILABLE;//類資訊運作時的使用的辨別位
    long instance_size                                       OBJC2_UNAVAILABLE;//執行個體變量大小
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;//成員變量清單
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;//方法清單
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;//方法緩存
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;//協定清單
#endif

} OBJC2_UNAVAILABLE;
           

下面定義兩個類,并以此舉例說明runtime

@interface Father : NSObject
@property (nonatomic, strong) NSString *property_1_s;
@property (nonatomic, weak) NSArray *property_2_w;
@property (nonatomic, unsafe_unretained) id property_3_un;
@property (nonatomic, weak) id property_4_w;
@property (nonatomic, strong) id property_5_s;
@property (nonatomic, strong) id property_6_s;
@property (nonatomic, unsafe_unretained) id property_7_un;
@property (nonatomic, strong) id property_8_s;
@property (nonatomic, strong) id property_9_s;
@property (nonatomic, weak) id property_10_w;
@property (nonatomic, weak) id property_11_w;
@property (nonatomic, strong) id property_12_s;
@property (nonatomic, weak) id property_13_s;
@end

@interface Son : Father

@end
Father *father = [[Father alloc] init];
Son *son = [[Son alloc]init];
           

(1)isa:指向metaClass(元類),元類顧名思義也是一個類,存儲對象的類方法。

NSLog(@"This object is %p.", son);
    Class currentClass = [son class];
    for (int i = ; i < ; i++)
    {
        NSLog(@"Following the isa pointer %d  times gives %p", i, currentClass);
        currentClass = object_getClass(currentClass);
    }
    NSLog(@"NSObject's class is %p", [NSObject class]);
    NSLog(@"NSObject's meta class is %p", object_getClass([NSObject class]));
           
知識總結Objective-C Runtime 運作時(1)

可以看出對象son的位址開辟在堆中,其類位址為0x109e80568,其isa指針指向的meta-class位址為0x109e80540,meta-class所屬類的位址為0x10ae38e58,通過列印NSObject的位址可以看出meta-class繼承了NSObject。

(2)super_class 指向父類,如果該類是最頂層根類如NSObject則其super_class為NULL。

(3)name 類名Father, Son

(4)version 該字段提供類的版本資訊,可以識别出不同定義版本中的執行個體變量布局的改變

(5)instance_size 執行個體變量大小

NSInteger instance_size = class_getInstanceSize([father class]);
NSLog(@"instance_size = %d",instance_size);
           
知識總結Objective-C Runtime 運作時(1)

father含有13個屬性都是指針類型和1個isa指針,一共112位元組。

(6)ivars 它指向objc_ivar_list結構體,objc_ivar_list其實就是一個連結清單,存儲多個objc_ivar,而objc_ivar結構體存儲類的單個成員變量資訊。

struct objc_ivar_list {
    int ivar_count                                           OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_ivar ivar_list[]                            OBJC2_UNAVAILABLE;
} 
           
unsigned int outCount =;
    Ivar*ivars =class_copyIvarList(father.class, &outCount);
    for(unsigned int i =; i < outCount; ++i) {
        Ivar ivar = ivars[i];
        const char*ivarName =ivar_getName(ivar);
        const char*ivarEncoder =ivar_getTypeEncoding(ivar);
        NSLog(@"Ivar name:%s Ivar TypeEncoder:%s",ivarName,ivarEncoder);
    }
    free(ivars);
           
知識總結Objective-C Runtime 運作時(1)

(7)methodLists表示方法清單,它指向objc_method_list結構體的二級指針,可以動态修改*methodLists的值來添加成員方法,也是category的實作原理。

struct objc_method_list {
    struct objc_method_list * _Nullable obsolete             OBJC2_UNAVAILABLE;

    int method_count                                         OBJC2_UNAVAILABLE;
#ifdef __LP64__
    int space                                                OBJC2_UNAVAILABLE;
#endif
    /* variable length structure */
    struct objc_method method_list[]                        OBJC2_UNAVAILABLE;
}
           

objc_method_list也是一個連結清單,存儲多個objc_method,而objc_method結構體存儲類的某個方法的資訊。

typedef struct objc_method *Method;  
struct objc_method {  
    SEL method_name                                          OBJC2_UNAVAILABLE;  
    char *method_types                                       OBJC2_UNAVAILABLE;  
    IMP method_imp                                           OBJC2_UNAVAILABLE;  
}
           

Method是一個指向objc_method結構體指針,它存儲了方法名(method_name)、方法類型(method_types)和方法實作(method_imp)等資訊。而method_imp的資料類型是IMP,它是一個函數指針

(8)cache用于緩存最近使用的方法。一個對象接收到一個消息時,對象會根據isa指針去查找能夠響應這個消息的對象。每次調用過一個方法後,這個方法就會被緩存到cache清單中,下次調用的時候runtime就會優先去cache中查找,如果cache沒有,才去methodLists中查找方法。這樣,對于那些經常用到的方法的調用,但提高了調用的效率。objc_cache結構體的指針,其定義如下:

struct objc_cache {
    unsigned int mask /* total = mask + 1 */                 OBJC2_UNAVAILABLE;
    unsigned int occupied                                    OBJC2_UNAVAILABLE;
    Method _Nullable buckets[]                              OBJC2_UNAVAILABLE;
};
           

(9)protocols類遵循的協定,協定清單objc_protocol_list定義如下:

typedef struct objc_object Protocol;//isa指針
struct objc_protocol_list {
    struct objc_protocol_list * _Nullable next;
    long count;
    __unsafe_unretained Protocol * _Nullable list[];
};
           

繼續閱讀