「宣言されていないセレクター」の警告を取り除く方法


162

実装されたプロトコルを必要とせずに、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



非推奨のセレクターは警告を引き起こします。セレクタはいつか削除される可能性があるため、セレクタにアクセスすることは安全ではありません。
DawnSong

回答:


254

別のオプションは、警告を無効にすることです:

#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

#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" // Do your thing #pragma clang diagnostic pop
dizy 2013

はい、それは@dizy状態として行います。(回答が遅れて申し訳ありませんが、通知を逃しました)。
Klaas 2013

私は必要alson#pragma clang diagnostic ignored "-Wselector"
最大

1
@mdorseifほとんどの場合、除外する必要のある警告はコンパイルログにリストされます。このコンセプトで警告をミュートできます。セレクターについて追加していただき、ありがとうございます。
Klaas 2013

@epologeeビルド設定「Undeclared Selector」を介して同じことを行うことができます

194

NSSelectorFromStringを見てください

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

これにより、コンパイル時に@selectorキーワードを使用する代わりに、実行時にセレクターを作成でき、コンパイラーが文句を言う機会がなくなります。


こんにちは@sergioさん、あなたと@jacobrelkinの両方の回答が機能します。ほぼ同時に提出されました。「より良い」答えがある場合は、それを選択してください。
epologee 2011年

2
「Cocoa」-y(?)に見えるので、私はこの回答がより好きです。sel_registerName()ブツルックスが不明瞭とあなたは何をやっている知っている限り、あなたが)(ちょっとobj_msg_sendのように、直接呼び出すべきではありません種類;)
ニコラ・Miari

15
Xcode 5かどうかはわかりませんが、この実装では「セレクターが不明なため、PerformSelectorによってリークが発生する可能性がありますという別の警告が表示されます。
Hampden123 2013年

1
@ Hampden123:それは別の問題です。ここを見て:stackoverflow.com/questions/7017281/...
セルジオ

52

これは、奇妙な理由でセレクタがランタイムに登録されていないためだと思います。

を介してセレクタを登録してみてくださいsel_registerName()

SEL setErrorSelector = sel_registerName("setError:");

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

こんにちは@jacobrelkinです。あなたと@sergioの両方の回答が機能します。ほぼ同時に提出されました。「より良い」答えがある場合は、それを選択してください。
epologee 2011年

2
とにかく、@ epologee NSSelectorFromStringが内部で呼び出しsel_registerName()ます。あなたに合った方を選んでください。
Jacob Relkin

1
@epologee sel_registerName()直接呼び出す方が、なぜそれをしているのかについてより明確であると思います。セレクターを登録しようとしていることNSSelectorFromStringわかりません。
Jacob Relkin

8
Xcode 5かどうかはわかりませんが、この実装では「セレクターが不明なため、PerformSelectorによってリークが発生する可能性がありますという別の警告が表示されます。
Hampden123 2013年

@ Max_Power89いいえ。以下の他のコメントを参照してください。あまり時間をかけたくなかったので、ヘッダーファイルを含めました。
Hampden123 2013年

7

メソッドでファイルを#includeすることで、このメッセージが消えます。そのファイルから他に使用されたものはありません。


これはあまり優雅な解決策ではありませんが、セレクタを受け取る可能性のある「既知の容疑者」がいるので、私にはうまくいきます。また、ランタイムセレクターアプローチを実装しても、performSelectorステートメントで別の警告が表示されます。つまり、「セレクターが不明であるため、PerformSelectorはリークを引き起こす可能性があります。ほんとありがと!
Hampden123 2013年

2
上位投票の回答はどちらも正しくありません。「宣言されていないセレクター」警告の目的は、依存していたセレクターの名前を変更した場合に、コンパイル時にエラーをキャッチすることです。したがって、依存していたメソッドを宣言するファイルを#importすることが最も適切です。
ブレーン、2014

7

私はこのスレッドに少し遅れていることを理解していますが、完全を期すために、ターゲットのビルド設定を使用してこの警告をグローバルにオフにすることができます。

セクション「Apple LLVM警告-Objective-C」で、次のように変更します。

Undeclared Selector - NO

6

クラスがsetError:メソッドを実装している場合(最終的なエラープロパティの動的セッターを宣言する場合でも)、それをインターフェイスファイル(.h)で宣言するか、そのように表示したくない場合があります。 PrivateMethodsのトリッキーなトリックを試してください:

@interface Yourclass (PrivateMethods)

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

@end

@implementationの直前で、これは警告を非表示にする必要があります;)。


おかげで、私はカテゴリからメソッドを呼び出しているので、これは適用されません。乾杯、EP。
epologee 2011年

そして、私たちの一部はよりエキゾチックなことをしています-私の場合、セレクターはF#オブジェクトに実装されています。
James Moore

1
これはXCode 7.1.1 / iOS 9.1の警告を取り除きません、私は見ることができますPerformSelector may cause a leak because its selector is unknown
loretoparisi '18年

3

本当に快適マクロは、あなたの中に入れて.pch、またはCommon.hあなたが好きな場所か:

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

同様の問題に対するこの質問の編集です...


3

あなたはスクリーンショットのようにXcodeでそれをオフにすることができます:

ここに画像の説明を入力してください


良いですね。それでも、「この場合はclangが間違っている、私は何をしているのかわかっている」と言って、明示的な場合にのみ警告を無効にすることを好みます。ご協力ありがとうございます。
epologee 2016年

2

警告を回避するために、問題のオブジェクトを最初にIDにキャストすることもできます。

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

1
これは、今日までのXC7.1まで、if式の内容に関する同じ警告を取り除きません。
Martin-Gilles Lavoie、2015年

2

この警告を回避する別の方法は、セレクターメソッドが次のようになることを確認することです。

-(void) myMethod :(id) sender{
}

送信者を受け入れる場合は「(id)送信者」を、必要に応じて送信者オブジェクトのタイプを指定することを忘れないでください。


0

正しい答えは、インポートを通じてXcodeに通知するか、そのようなセレクターが存在することをセレクターに登録することですが、私の場合、セミコロンがありませんでした。エラーを「修正」する前に、おそらくエラーが正しく、コードが正しくないことを確認してください。たとえば、AppleのMVCNetworkingサンプルにエラーが見つかりました。


いいえ、インポートによってXcodeに通知されたのは正しい答えではありませんでした。正しい答えは、正しい答えとしてマークされた上記の答えでしたが、@ sergioの答えも問題を解決します。間違ったセレクターを使用することはこの質問の主題ではないため、セレクターを変更しても答えにはなりません。私はあなたに反対投票を保存します。
epologee 2013年

1
おそらくコメントを使用するべきだったことを思い出させてくれてありがとう。私が言えることは、インポートが欠落していると、この特定のインスタンスではないにしても、このXcode警告が発生するということです。実行時にセレクターを構築するとき、または動的な方法でメソッド呼び出しに応答するとき(たとえばmethodSignatureForSelector)、NSSelectorFromStringまたはその他の「登録」オプションのみをお勧めします。登録それはあなたが「エラーを回避作業」など、より正確なアプローチが警告を修正することになるので、いくつかの事情のために正しくないですね意味(打ち鳴らす分析があること、正しかった場合。)
ルイサンタムール

実際、元の質問は「実装されたプロトコルの必要なし」と明確に言っていることがわかり、インポートについてはまったく触れられていません。したがって、カテゴリ自体をインポートすることは、このユーザーにとって最良のオプションである可能性があると私は思います。技術的に言えば、ここで他の何かはセレクターを2回定義できます。はい?-編集:ああ、私はこれを取りすぎた。お返事ありがとうございます。:)
Louis St-Amour

-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
{

}

警告を非表示にする方法を知っていることに感謝しますが、警告を修正することはより良い方法であり、理由は不明ですが、セルジオの手法もレルキンの手法もうまくいきませんでした。


1
他の誰かがこの解決策を読んだ場合、それは機能しますが、彼/彼女はあなたの将来の自分を含めてかなり混乱します。存在しないセレクターを呼び出して何をしているのかを確認しているために警告が表示される場合は、誤解を招くメソッドスタブをスキップして、コードが意図を表現していることを確認してください。
epologee 2014

1
いい視点ね。私は継承されたコードで作業していて、なぜ存在しないセレクタがあるのか​​という基本的な問題を解決しようとせず、警告を消す方法を見つけようとしていました。一度に一歩ずつ、私はいつも言っています。
user938797 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.