說到Objc執行時,如果你還不清楚,那可要看仔細了,如果你是靠顏值而不是才華能夠順利通過面試,喵了個咪的,我也想去試試
Objc執行時2.0
iOS出現時就是執行時2.0版本了,和舊的相比擁有兩大特性:
第一,就是修改,增加或刪除一個類的例項變數,不用再重新編譯子類就可以用了。
第二,就是加為@property加入了Synthesize
實戰問題一(答案在最後):
請將屬性property(atomic,nonatomic, assign, weak, strong, copy, readonly, readwrite blah!blah!)按照功能分組
實戰問題二(答案在最後):
請回答下列@property變數cool和cat的預設屬性
@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:)];
執行時:
`objc_msgSend(receiver, selector, arg1)`
objc_msgSend做的事情如下:
-
根據receiver和selector先在receiver的方法派遣表裡面查詢是否有selector這個方法實現, 如果沒找到,receiver->isa->superclass去查詢,以此類推,直到找到對應的方法實現,若直到NSObject都沒有找到對應實現,中間過程在下文解釋,最後掉用
[receiver doesNotRecognizeSelector:_cmd]
就拋異常出錯了 -
將所有引數傳給具體實現方法呼叫
-
將具體實現結果反回來
跳過執行時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
", 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
*/