我通过在运行时选择最新的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
?
在看到一些答案之后,让我澄清一下,混淆编译器而不知道我在做什么并不是一个有效的解决方案。
答案 0 :(得分:115)
我在Clang编译器用户手册中找到了an example,让我忽略了警告:
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
}
答案 1 :(得分:8)
您可以声明一个指定用于调用弃用方法的单独文件,并在Xcode中设置每个文件编译器标志以忽略-Wdeprecated-declarations
。然后,您可以在该文件中定义虚拟函数以调用已弃用的方法,从而避免实际源文件中的警告。
答案 2 :(得分:6)
我不确定clang是否足够智能来捕获它,但如果不是,则可以尝试使用performSelector:withObject:withObject:
或构建并调用NSInvocation对象。
答案 3 :(得分:5)
你可以将fileManager
转换为id
- ids
能够引用任何Objective-C对象,因此编译器不应该检查被调用的方法之一:
[(id)fileManager removeItemAtPath:downloadDir error:NULL];
不应提出任何警告或错误。
当然,这会引发其他问题 - 即,您在id
上调用的方法会丢失所有编译时检查。因此,如果您拼错了方法名称等,则在执行该行代码之前不会被捕获。
答案 4 :(得分:3)
如果您认为任何形式的“混淆”编译器都是无效的解决方案,您可能不得不接受警告。 (在我的书中,如果你问如何摆脱警告,在口中看到一匹礼物马是不明智的,只是因为看起来不像你期望的那样,说某些东西是无效的。)
在运行时工作的答案涉及屏蔽动态调度所发生的操作,因此编译器不会抱怨已弃用的调用。如果您不喜欢这种方法,可以在Xcode项目或目标设置中关闭“警告关于不推荐使用的功能”,但这通常是个坏主意。您想了解已弃用的API,但在这种情况下,您希望在不发出警告的情况下使用它。有很简单的方法可以做到这一点,你可能会认为它们在某种形式下都是“无效的”,但这并不妨碍它们有效,甚至是正确的。 ; - )
避免警告但仍然在运行时选择的一种可能方法是直接使用objc_msgSend()
:
objc_msgSend(fileManager, @selector(removeFileAtPath:error:), downloadDir, nil];
This is what the Objective-C runtime does under the covers anyway,并且应该以最小的麻烦完成你想要的结果。为清晰起见,您甚至可以将原始行留在其上方。我知道文档说,“编译器会生成对消息传递函数的调用。你永远不应该直接在你编写的代码中调用它。”你必须决定何时可以修改规则。< / p>