在 object-c 中,selector 包含兩種意義:在源檔案中,它指向一個方法調用,在編譯後它指向一個 unque indentifier。
編譯後的 selector 的類型為 SEL,同名的方法的選取器也相同。
使用 selector 來調用object 方法是 Cocoa 架構 "目標-動作" 編程模型的基礎。
可以使用 @selector 來為 selector 建立一個別名:
SEL setWidthHeight;
setWidthHeight = @selector(setWidth:height:);
在編譯時間用別名方法引用 seletor 不會對效能造成大的影響。如果是運行時需要根據一個字會串動態決態調用哪個方法可以下面的形式,有點類似於反射:
NSString *method;
method = NSStringFromSelector(setWidthHeight);
關於方法和選取器
架構只為 selector 分配 identifier 鴯 不是方法的實現,因此不同 class 的同名方法雖然 selector 的 identifier 一樣,但是在執行是與方法調用無異。同時靜態方法也可以與動態方法重名,因為他們有不同的歸屬對象。
動態類型標註時,同名方法必須是相同的參數類型與傳回值,而靜態類型標註時不需要。這是因為靜態類型標註時可以通過類的中繼資料得知方法的實現。
除此之外,靜態方法和執行個體方法也不受此限制,他們存在於不同的空間。
id helper = getTheReceiver();
SEL request = getTheSelector();
[helper performSelector:request];
如些的動態調用顯得很強大。
[myButtonCell setAction:@selector(reapTheWind:)];
[myButtonCell setTarget:anObject];
上面的代碼示範了如何將按鈕和事件處理對象進行關聯
雖然有一些手段使用動態 message 來維護按鈕與事件處理對象的關係,但是蘋果認為那會帶來不必要的複雜性,因此使用了目前這種方式。
為了避免對象接受到它不能處理的訊息,多用靜態標註類型總是好的,因為它可以在編譯時間被檢查。
如果一定要在運行時調用一個不能確定的方法,那麼可以用這樣的方式進行測試,以進行安全調用而不是報錯:
if ( [anObject respondsToSelector:@selector(setOrigin::)] )
[anObject setOrigin:0.0 :0.0];
else
fprintf(stderr, "%s can’t be placed\n",
[NSStringFromClass([anObject class]) UTF8String]);
另外,當對象不能處理一個訊息時,它可以對它進行轉寄。詳見 訊息轉寄: http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtForwarding.html#//apple_ref/doc/uid/TP40008048-CH105