2012-05-28 171 views
13

所以,我一直在與objc運行時插科打諢再次(驚喜驚喜),我發現的代碼here一個有趣的塊:爲什麼我們不能使用C字符串作爲SEL?

const char *sel_getName(SEL sel) { 
#if SUPPORT_IGNORED_SELECTOR_CONSTANT 
    if ((uintptr_t)sel == kIgnore) return "<ignored selector>"; 
#endif 
    return sel ? (const char *)sel : "<null selector>"; 
} 

那麼,這是什麼告訴我的是,一個SEL相當於以C字符串,在每個習慣做法。做前16個字節包含@selector(addObject:) SEL中的十六進制轉儲給出以下:

61 64 64 4F 62 6A 65 63 74 3A 00 00 00 00 00 00

其等於C字符串addObject:

這樣說,爲什麼當我使用C字符串作爲選擇器時,此代碼崩潰?

SEL normalSEL = @selector(addObject:); 
SEL cStringSEL = (SEL) "addObject:"; 

NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1", @"2", nil]; 

[arr performSelector:normalSEL withObject:@"3"]; 
[arr performSelector:cStringSEL withObject:@"4"]; 

NSLog(@"%@", arr); 

據我所知道的,選擇的內容是相同的,那麼,爲什麼在第二個與以下錯誤消息的崩潰?

***終止應用程序由於未捕獲的異常 'NSInvalidArgumentException', 原因: ' - [__ NSArrayM ADDOBJECT:]:無法識別的選擇發送到實例 0x101918720' ***

+3

請注意,您可以使用'sel_registerName()'將一個C字符串變成一個有福的SEL(它基本上不區分背後的字符串以保留後續的指針標識)。還要注意,你永遠不應該直接依賴一個作爲char *的SEL。它可能總是會的,但這並不能使這個假設正確。 – bbum

回答

22

選擇器被拘留C字符串,並且比較他們的地址,而不是他們的內容。字符串內容僅用於轉換爲/從外部字符串表示形式。實施Interning是爲了提高性能 - 當運行時查找匹配選擇器的方法實現時,它可以直接比較選擇器指針,而不是取消引用每個指針並比較字符。

+0

嗯...看着'__sel_registerName'後我相信你是對的。儘管如此,我還是想知道這樣做會帶來多大的性能差異...... –

+0

這也是字符串/選擇器API強烈暗示的;請參閱['NSSelectorFromString()']的文檔(https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_Functions/Reference/reference.html#//apple_ref/doc/) uid/20000055-BCIEICGB)及其與'sel_registerName()'的連接。 –

+13

objc_msgSend最近運行了大約8個週期。那裏沒有很多strcmp()的空間;) –

相關問題