当使用respondsToSelector时,禁止使用“'…'”

我通过在运行时select最新的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] 

是否有语法if([… respondsToSelector:@selector(…)]){ … } else { … }提示编译器(Clang)不要在该行发出警告?

如果没有,是否有一种方法来标记该行忽略-Wdeprecated-declarations


在看到一些答案之后,让我澄清一点,混淆编译器不知道我在做什么不是一个有效的解决scheme。

我在Clang编译器用户手册中find一个例子 ,让我忽略这个警告:

 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 } 

您可以声明一个单独的文件,指定用于调用废弃的方法,并将Xcode中的每个文件编译器标记设置为忽略-Wdeprecated-declarations 。 然后,您可以在该文件中定义一个虚拟函数来调用已弃用的方法,从而避免实际源文件中的警告。

我不确定clang是否足够聪明来捕捉这个,但是如果不是,你可以尝试使用performSelector:withObject:withObject:或者构build和调用一个NSInvocation对象。

您可以将fileManager转换为idids可以引用任何Objective-C对象,因此编译器不应该检查在其中调用的方法:

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

不应该提出任何警告或错误。

当然,这会引发其他的问题 – 也就是说,你失去了所有编译时检查id方法。 所以如果你拼错你的方法名称等,它不会被捕获,直到该行代码执行。

如果你认为任何forms的“混淆”编译器是一个无效的解决scheme,你可能不得不忍受这个警告。 (在我的书中,如果你问如何摆脱警告,那么在马上看礼物是不明智的,因为它看起来不像你期望的那样,所以说一些东西是无效的。)

在运行时工作的答案涉及屏蔽dynamic调度发生的操作,所以编译器不会抱怨不推荐的调用。 如果你不喜欢这种方法,你可以在你的Xcode项目或目标设置中closures“弃用函数的警告”,但这通常是一个坏主意。 你想知道不赞成使用的API,但在这种情况下,你想使用它没有任何警告。 要做到这一点有一些简单的和困难的方法,你可能会认为所有这些都是某种forms的“无效”,但这并不妨碍它们的有效性,甚至是正确的。 😉

避免警告仍然在运行时select的一种方法是直接使用objc_msgSend()

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

这就是Objective-C运行时在底层所做的事情,并且应该用最less的麻烦来完成你想要的结果。 为了清晰起见,您甚至可以将原始行注释掉。 我知道文档说: “编译器生成对消息函数的调用,你不应该直接在你写的代码中调用它。 你必须决定什么时候可以弯曲规则。