2011-06-03 118 views
148

我想在NSObject實例上使用選擇器而不是需要實現的協議。例如,有一個類別方法應該設置一個錯誤屬性,如果它調用的NSObject實例支持它。這是代碼,而該代碼按預期工作:如何擺脫'未聲明的選擇器'警告

if ([self respondsToSelector:@selector(setError:)]) 
{ 
    [self performSelector:@selector(setError:) withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]]; 
} 

然而,編譯器沒有發現任何方法與SETERROR圍:簽名,所以它給了我一個警告,對於包含@selector(setError:)每一行片段:

Undeclared selector 'setError:' 

我不希望有申報協議擺脫這一警告的,因爲我不希望出現這種情況可能會藉此實現什麼特別的所有類。按照慣例,我希望他們有一個setError:方法或財產。

這是可行的嗎?怎麼樣?

乾杯,
EP

+1

的解決方案是很好解釋[performSelector可能會導致泄漏,因爲它的選擇器是未知](http://stackoverflow.com/questions/7017281/performselector-may-cause-a-leak-because-its-selector-is-unknown) – loretoparisi 2015-11-18 12:01:43

回答

223

另一種選擇是使用禁用的警告:

#pragma GCC diagnostic ignored "-Wundeclared-selector" 

你可以把這個線在報警發生.m文件。

更新:

它的工作原理也與LLVM是這樣的:

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "-Wundeclared-selector" 

... your code here ... 

#pragma clang diagnostic pop 
+1

對LLVM也這樣做嗎? – epologee 2012-05-09 12:42:07

+0

'#pragma clang診斷推送'# '#pragma clang診斷忽略「-Wundeclared-selector」' '//做你的事情' '#pragma clang diagnostic pop' – dizy 2013-08-21 03:50:34

+0

yes,它的確如@dizy所述。 (對不起,對於遲到的回答,但我錯過了通知)。 – Klaas 2013-08-21 14:28:05

175

看一看NSSelectorFromString

SEL selector = NSSelectorFromString(@"setError:"); 
if ([self respondsToSelector:selector]) 

它可以讓你在運行時通過@selector關鍵字創建一個選擇,而不是在編譯時,編譯器就沒有機會抱怨。

+0

嗨@ sergio,你和@ jacobrelkin的答案都有效。幾乎同時提交。如果有的話,你能幫我選擇'更好'的答案嗎? – epologee 2011-06-03 09:18:39

+2

我更喜歡這個答案,因爲它看起來更「可可」-y(?)。 'sel_registerName()'thingy看起來很模糊,你不應該直接調用,除非你知道你在做什麼,有點像obj_msg_send();) – 2013-09-16 15:18:16

+14

不知道它是否是Xcode 5,但我得到了一個不同的警告這個實現:_「PerformSelector可能導致泄漏,因爲它的選擇器是未知的」_。 – Hampden123 2013-11-20 16:38:20

50

我認爲這是因爲某些奇怪的原因,選擇器沒有註冊運行時。

嘗試通過sel_registerName()註冊的選擇:

SEL setErrorSelector = sel_registerName("setError:"); 

if([self respondsToSelector:setErrorSelector]) { 
    [self performSelector:setErrorSelector withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]]; 
} 
+0

嗨@jacobrelkin,你和@塞爾吉奧的答案工作。幾乎同時提交。如果有的話,你能幫我選擇'更好'的答案嗎? – epologee 2011-06-03 09:18:16

+2

@epologee'NSSelectorFromString'無論如何都會調用'sel_registerName()'。選擇適合你的更好的。 – 2011-06-03 09:24:38

+1

@epologee我認爲直接調用'sel_registerName()'會更明確地說明你爲什麼要這樣做。 'NSSelectorFromString'不會告訴你它將嘗試註冊選擇器。 – 2011-06-03 09:26:16

5

如果你的類實現了SETERROR:方法(甚至通過聲明動態最終錯誤setter方法),你可能想聲明它在你的接口文件( .H),或者如果你不喜歡錶露出來這樣你可以與PrivateMethods狡猾伎倆嘗試:

@interface Yourclass (PrivateMethods) 

- (void) yourMethod1; 
- (void) yourMethod2; 

@end 

只是你的@implementation之前,本應隱藏的警告)。

+0

謝謝,但我從類別中調用方法,所以這不適用。乾杯,EP。 – epologee 2011-06-03 10:06:24

+0

我們中的一些人正在做更奇特的事情 - 在我的情況下,選擇器是在F#對象中實現的。 – 2013-10-21 23:00:34

+1

這並沒有擺脫XCode 7.1.1/iOS 9.1中的警告,我可以看到'''PerformSelector可能導致泄漏,因爲它的選擇器是未知的'' – loretoparisi 2015-11-18 11:46:08

0

而正確的答案可能就在於通過進口通知的Xcode或這樣的選擇存在,註冊選擇在我我錯過了一個分號。確保在「修復」錯誤之前,可能錯誤是正確的,而你的代碼不正確。例如,我在Apple的MVCNetworking樣本中發現錯誤。

+0

不,正確的答案並不是通過導入來通知Xcode,因爲這些導入已經到位。正確的答案是上面的答案被標記爲......正確的答案,儘管@塞爾吉奧的答案也能解決問題。使用*錯誤*選擇器不是這個問題的主題,因此更改選擇器不是答案。儘管如此,我會爲你節省下來。 – epologee 2013-10-23 11:29:46

+1

感謝提醒我,我可能應該使用評論。我只能說缺少的進口也會導致這種Xcode警告,如果不是這個特定的實例。在運行時構建選擇器或以動態方式響應方法調用(例如methodSignatureForSelector)時,我只會推薦使用NSSelectorFromString或其他此類「註冊」選項。註冊意味着你正在「解決錯誤」,所以在某些情況下是不正確的,因爲更正確的方法是修復警告(如果叮聲分析是正確的,那就是) – 2013-10-28 19:47:33

+0

事實上,我現在看到原來的問題清楚地表明,「不需要執行協議」 - 並且根本沒有提及進口。所以我會提出導入類別本身可能是這個用戶的最佳選擇。從技術上講,這裏的其他任何東西都可以定義選擇器兩次。是? - 編輯:啊,我已經採取了這個太遠。感謝您的迴應,我現在就停下來。 :) – 2013-10-28 19:50:37

6

我得到了這個消息,通過包含與該方法的文件消失。該文件中沒有其他使用。

+0

雖然這不是一個優雅的解決方案,但它適用於我,因爲我有可能正在接收選擇器的「已知嫌疑人」。另外,如果我實現了運行時選擇器方法,我仍然會在performSelector語句中得到不同的警告;即_「PerformSelector可能導致泄漏,因爲其選擇器未知」_。那謝謝啦! – Hampden123 2013-11-20 16:31:49

+2

最高投票答案都是正確的。 「未聲明的選擇器」警告的目的是在編譯時發現錯誤,如果你改變了你所依賴的選擇器的名字。因此,#import聲明您所依賴的方法的文件是最正確的。 – Brane 2014-02-18 16:04:42

3

一個真正舒適的宏觀把你.pchCommon.h或任何你想要的:

#define SUPPRESS_UNDECLARED_SELECTOR_LEAK_WARNING(code)      \ 
_Pragma("clang diagnostic push")          \ 
_Pragma("clang diagnostic ignored \"-Wundeclared-selector"\"")  \ 
code;                 \ 
_Pragma("clang diagnostic pop")           \ 

它的this question類似的問題編輯...

1

您也可以投對象的問題以id爲第一,以避免警告:

if ([object respondsToSelector:@selector(myMethod)]) { 
    [(id)object myMethod]; 
} 
+0

這並沒有擺脫if表達式內容的相同警告,一直到XC7.1到今天。 – 2015-10-26 20:11:28

-1

我能夠通過添加齒輪來消除警告方法(披露:我沒有想到這一點,但發現通過谷歌搜索上scheduledtimerwithtimeinterval)

[NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow] 
            target:self 
            selector:@selector(donothingatall:) 
            userInfo:nil 
            repeats:YES]; 


    [[NSRunLoop currentRunLoop] run]; 

    HTTPLogVerbose(@"%@: BonjourThread: Aborted", THIS_FILE); 

    } 
} 

+ (void) donothingatall:(NSTimer *)timer 
{ 

} 

雖然我很欣賞知道如何隱藏警告,修復它更好,既不是Sergio的也不Relkin的技術爲我工作,原因不明。

+0

如果有人讀這個解決方案,哪個*會工作*,他/她會相當困惑,包括你未來的自我。如果您確定通過調用不存在的選擇器來知道自己在做什麼,從而引發警告,請跳過誤導方法存根並確保代碼表達您的意圖。 – epologee 2014-12-07 12:01:20

+1

好點。我正在使用繼承的代碼,並試圖弄清楚如何使警告消失,而不是試圖解決爲什麼有一個不存在的選擇器的基本問題。我總是說一次一步。 – user938797 2014-12-08 18:54:50

7

我意識到我對這個主題有點晚了,但爲了完整性,您可以使用目標構建設置全局關閉此警告。

在本條中, '蘋果LLVM警告 - Objective-C的',更改:

Undeclared Selector - NO 
2

您可以在截圖關閉它在Xcode中,如:

enter image description here

+0

不錯的一個。儘管如此,我寧願禁用警告只是爲了明確的情況下,通過說「叮噹是在這個場合是錯誤的,我知道我在做什麼」。感謝您的輸入! – epologee 2016-10-12 21:38:00