web-dev-qa-db-ja.com

respondsToSelectorの使用時に「 '…'は非推奨」の抑制

実行時に最新のAPIを選択することで10.4以降をサポートしています。

_if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)])
    [fileManager removeItemAtPath:downloadDir error:NULL];
else
    [fileManager removeFileAtPath:downloadDir handler:nil];
_

この場合、10.5以降は_removeItemAtPath:error:_を使用し、10.4は_removeFileAtPath:handler:_を使用します。すばらしいですが、古いメソッドに対してコンパイラの警告が表示されます。

_warning: 'removeFileAtPath:handler:' is deprecated [-Wdeprecated-declarations]
_

コンパイラー(Clang)にその行で警告しないように指示するif([… respondsToSelector:@selector(…)]){ … } else { … }の構文はありますか?

そうでない場合、その行に_-Wdeprecated-declarations_を無視するタグを付ける方法はありますか?


いくつかの回答を確認した後、コンパイラーを混乱させて私が何をしているのかわからないようにするのは有効な解決策ではないことを明確にしましょう。

56
s4y

Clangコンパイラのユーザーマニュアルで が見つかり、警告を無視できます。

if ([fileManager respondsToSelector:@selector(removeItemAtPath:error:)]) {
    [fileManager removeItemAtPath:downloadDir error:NULL];
} else {
#pragma clang diagnostic Push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
    [fileManager removeFileAtPath:downloadDir handler:nil];
#pragma clang diagnostic pop
}
116
s4y

廃止されたメソッドを呼び出すために指定された個別のファイルを宣言し、Xcodeでファイルごとのコンパイラフラグを設定して-Wdeprecated-declarationsを無視することができます。次に、そのファイルでダミー関数を定義して非推奨のメソッドを呼び出すことができます。これにより、実際のソースファイルの警告を回避できます。

8
kperryua

Clangがこれをキャッチするのに十分スマートかどうかはわかりませんが、そうでない場合は、performSelector:withObject:withObject:を使用するか、NSInvocationオブジェクトを作成して呼び出してみてください。

6
Martin Gordon

fileManageridにキャストすることができます— idsは任意のObjective-Cオブジェクトを参照できるため、コンパイラーは呼び出されるメソッドをチェックする必要はありません1:

[(id)fileManager removeItemAtPath:downloadDir error:NULL];

すべきではない警告またはエラーを発生させます。

もちろん、これにより他の問題が発生します。つまり、idで呼び出されるメソッドのコンパイル時チェックallが失われます。したがって、メソッド名などのスペルを間違えた場合、そのコード行が実行されるまでキャッチされません。

5
Matt Ball

コンパイラーを「混乱させる」何らかの形が無効なソリューションであると考える場合、おそらく警告に耐えなければならないでしょう。 (私の本では、警告を取り除く方法を尋ねる場合、贈り物の馬を口で見て、期待したように見えないという理由だけで何かが無効であると言うのは賢明ではありません。)

実行時に機能する回答には、動的ディスパッチで発生する操作をマスクするため、非推奨の呼び出しについてコンパイラーが文句を言わないようにします。そのアプローチが気に入らない場合は、Xcodeプロジェクトまたはターゲット設定で「非推奨の関数について警告」をオフにすることができますが、これは一般に悪い考えです。廃止されたAPIについて知りたいが、この場合は警告なしで使用したい。これを行うには簡単な方法と難しい方法があり、それらのすべてを何らかの形で「無効」と見なす可能性がありますが、それでもそれらが効果的であること、正しいことを妨げるものではありません。 ;-)

警告を回避しながら実行時に選択する方法の1つは、objc_msgSend()を直接使用することです。

objc_msgSend(fileManager, @selector(removeFileAtPath:error:), downloadDir, nil];

これはとにかくObjective-Cランタイムがカバーしていることです であり、最小限の手間で目的の結果を達成できるはずです。明確にするために、元の行の上にコメントを残すこともできます。 「コンパイラはメッセージング関数への呼び出しを生成します。記述するコードで直接呼び出すことはできません。」いつルールを曲げてもいいかを決定します。

3
Quinn Taylor