2013-09-27 76 views
3

當你擁有的是代理對象時,有什麼方法可以測試選擇器/方法嗎?如何測試Objective-C中代理對象的選擇器?

/* Proxy which may forward 
* the method to some other object */ 
id proxy = [UINavigationBar appearance]; 

/* This condition returns FALSE 
* despite the fact that the method would have otherwise been 
* successfully executed at its destination */ 
if([proxy respondsToSelector:@selector(setBarTintColor:)]){ 
    [proxy setBarTintColor:color]; 
} 
+0

@maddy這就是爲什麼我試圖找到一種方法來測試方法調用是否會在調用之前成功 - 而不是基於操作系統版本的邏輯.. – sean

回答

2

顯然你不能。

通過其他的答案提出的方法,將打破很容易,這裏有一個例子:

  • UINavigationBar情況下,應對選擇器setTranslucent:
  • 但是setTranslucent:沒有在頭文件標有UI_APPEARANCE_SELECTOR

因此下面的代碼

if([[UINavigationBar class] instancesRespondToSelector:@selector(setTranslucent:)]) { 
    [[UINavigationBar appearance] setTranslucent:NO]; // BUM! 
} 

將導致崩潰。

關於哪個選擇器符合UIAppearance的唯一信息似乎是UI_APPEARANCE_SELECTOR宏,它在編譯時被剝離。

運行時檢查看起來不可行。


爲了完整起見,這裏做的可怕(但實用)的方式。

@try { 
    [[UINavigationBar appearance] setTranslucent:YES]; 
} @catch (NSException *exception) { 
    if ([exception.name isEqualToString:@"NSInvalidArgumentException"]) 
     NSLog(@"Woops"); 
    else 
     @throw; 
} 

然而,這是非常脆弱的,因爲誰也不能保證,你捉只在其中選擇不符合UIAppearance的情況。

+1

好的,你確實指出它是一個可怕的建議,但它的罰款沒有例外塊。不要吞下異常 - 讓它崩潰並快速失敗,並讓開發人員知道它不起作用。對於這種情況,這是比編譯器告訴開發者無法正常工作的情況下最好的事情。 – bandejapaisa

+1

我在你下面寫的同一回答。重點是執行運行時檢查,而不是檢測代理支持哪些方法。爲此,我們有文檔和標題。 –

1

最好的辦法似乎是

  1. 確保有關財產在頭與UI_APPEARANCE_SELECTOR定義。
  2. 在針對類UINavigationBar本身的代碼測試,而不是它的外觀

    if ([(some UINavigationBar object) respondsToSelector:@selector(setBarTintColor:)])... 
    

或,作爲另一答案提示,

if ([UINavigationBar.class instancesRespondToSelector:@selector(setBarTintColor:)])... 

雖然理論上proxy是一個不同的目的類,外觀代理似乎是由Apple自動生成的標記爲UI_APPEARANCE_SELECTOR的方法生成的。正如UIAppearance.h中的評論所述:

要參與外觀代理API,請在標頭中用UI_APPEARANCE_SELECTOR標記外觀屬性選擇器。

如果您爲通過舊版iOS中的外觀代理可用的屬性實現該方法,但稍後從代理中刪除該屬性,則此方法將中斷。在同一個文件中記錄了一個這樣的例子:

在iOS7上... tintColor現在不允許使用外觀代理。

因此,您確實需要測試罕見的情況以確保代碼不會被新的iOS破壞,但您仍然無需手動編寫版本號。