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]));
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiQ3chVEa0V3bT9CX5RXa2Fmcn9CXwczLcVmds92czlGZvwVP9EUTDZ0aRJkSwk0LcxGbpZ2LcBDM08CXlpXazRnbvZ2LcRlMMVDT2EWNvwFdu9mZvwFeBRUT0UlaNRTT6hVdsdUZwZlMkZXUYpVd1kmYr50MZV3YyI2cKJDT29GRjBjUIF2LcRHelR3LcJzLctmch1mclRXY39jN5kTNxADNyEDNxITM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
可以看出對象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);
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);
(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[];
};