死磕Objective-C runtime運行時之一

說到Objc運行時,若是你還不清楚,那可要看仔細了,若是你是靠顏值而不是才華可以順利經過面試,喵了個咪的,我也想去試試html

Objc運行時2.0

iOS出現時就是運行時2.0版本了,和舊的相比擁有兩大特性:
第一,就是修改,增長或刪除一個類的實例變量,不用再從新編譯子類就能夠用了。
第二,就是加爲@property加入了Synthesizeios

實戰問題一(答案在最後):

請將屬性property(atomic,nonatomic, assign, weak, strong, copy, readonly, readwrite blah!blah!)按照功能分組git

實戰問題二(答案在最後):

請回答下列@property變量cool和cat的默認屬性github

@interface ViewController : UIViewController

@property BOOL cool;
@property NSObject *cat;

@end

Objc運行時

Objc運行時至關於Objective-C的操做系統,當咱們編譯代碼時,編譯器把源碼編譯成運行時可以懂得數據結構(好比isa包括類的繼承信息)和運行時方法(好比objc_msgSend), 剩下的就交給運行時動態處理了。面試

NSObject成員變量isa

@interface NSObject{
    objc_class *isa
}

//點開isa連接搜索struct objc_class : objc_object可以查到其聲明
struct objc_class : objc_object {
    // Class ISA;
    objc_class *superclass;
    ....
    方法派遣表   selector對應的C語言函數
    ....
}

從objc_class聲明能夠看出,每個isa->superclass一樣是objc_class類型,
這樣就組成了一個繼承的鏈表結構

運行時3種使用方式

1.寫Objective-C代碼必然用到,雖然沒這種感受
2.調用NSObject運行時方法
3.直接調用運行時API緩存

運行時objc_msgSend

objc方法只不過是C語言方方法,加上兩個特殊的參數第一個是receiver(self),第二個參數是selector(_cmd)數據結構

好比如下的方法調用
[receiver message:arg1] //假設定義arg1爲BOOL類型
具體實現:
(void (*)(id, SEL, BOOL))[target methodForSelector:@selector(message:)];
運行時:app

`objc_msgSend(receiver, selector, arg1)`

objc_msgSend作的事情以下:ide

  1. 根據receiver和selector先在receiver的方法派遣表裏面查找是否有selector這個方法實現, 若是沒找到,receiver->isa->superclass去查找,以此類推,直到找到對應的方法實現,若直到NSObject都沒有找到對應實現,中間過程在下文解釋,最後掉用[receiver doesNotRecognizeSelector:_cmd]就拋異常出錯了函數

  2. 將全部參數傳給具體實現方法調用

  3. 將具體實現結果反回來

跳過運行時objc_msgSend

儘管objc_msgSend在成功調用一次方法以後,每一個Class會有緩存,下次重複調用該方法時,查找速度會大大提升,可是仍是有運行時消息發送的時間,若是一個函數被調用成千上萬次,爲了減小消息派遣時間,能夠跳過運行時objc_msgSend,直接調用方法實現

void (*message)(id, SEL, BOOL);
int i;
 
message = (void (*)(id, SEL, BOOL))[target
    methodForSelector:@selector(message:)];
for ( i = 0 ; i < 1000 ; i++ )
    setter(targetList[i], @selector(message:), YES);

問題一答案:

原子性:atomic,nonatomic
讀寫性: readwrite, readonly
ARC版內存管理: assign, strong, copy, weak

問題二答案:

@property cool = TB,V_cool
@property cat = T@"NSObject",&,V_cat

子問題1: 你是怎麼獲得答案的?答案就是用運行時啦!!!

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    
    id LenderClass = objc_getClass("ViewController");
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList(LenderClass, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        fprintf(stdout, "@property %s = %s\n", property_getName(property), property_getAttributes(property));
    }
}

子問題2: 如何解讀?首先說明這奇怪的字符時編譯器乾的好事啦,參考主要是這裏還有這裏

The string returned by |property_getAttributes| starts with a T followed by the @encode type and a comma, and finishes with a V followed by the name of the backing instance variable.

上面一坨就是說,property_getAttributes得到的字符串的格式,以T開頭,而後是<變量類型>,而後是一個逗號,而後是<屬性>,最後是一個V,再日後就是下劃線_和變量名了

/*根據文檔:
若是是readonly應該有R屬性, 因此默認應該是readwrite
若是是weak,strong,copy應該分別有W, &, C, 因此默認應該是assign
若果有nonatomic應該有N, 因此默認是atomic       

TB,V_cool B表明BOOL, 中間什麼屬性都沒有對不對,根據以上分析,默認是atomic, assign, readwrite 
T@"NSObject",&,V_cat 則是atomic, strong, readwrite
*/
相關文章
相關標籤/搜索