57

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


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

4

5 回答 5

118

我在 Clang Compiler User's Manual 中找到了一个示例,可以让我忽略警告:

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
}
于 2009-12-14T16:54:13.913 回答
8

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

于 2009-12-14T16:57:58.447 回答
6

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

于 2009-12-14T17:35:28.777 回答
5

您可以只强制fileManager转换为id-ids能够引用任何 Objective-C 对象,因此编译器不应该检查在一个对象上调用的方法:

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

不应引发任何警告或错误。

当然,这会引发其他问题——即,您失去对在id. 因此,如果您拼错了方法名称等,则在执行该行代码之前不会被捕获。

于 2009-12-14T20:33:33.230 回答
3

如果您认为任何形式的“混淆”编译器都是无效的解决方案,那么您可能不得不忍受警告。(在我的书中,如果你问如何摆脱一个警告,那是不明智的,因为它看起来不像你所期望的那样,就在嘴里看着一匹礼物马并说某些东西是无效的。)

在运行时有效的答案涉及屏蔽动态调度发生的操作,因此编译器不会抱怨不推荐使用的调用。如果您不喜欢这种方法,您可以在您的 Xcode 项目或目标设置中关闭“警告已弃用函数”,但这通常是个坏主意。您想了解已弃用的 API,但在这种情况下,您想在没有警告的情况下使用它。有一些简单和困难的方法可以做到这一点,而且您可能会认为所有这些方法都以某种形式“无效”,但这并不妨碍它们有效,甚至是正确的。;-)

避免警告但仍然在运行时选择的一种可能方法是objc_msgSend()直接使用:

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

无论如何,这就是 Objective-C 运行时所做的事情,并且应该以最少的麻烦完成您想要的结果。为了清楚起见,您甚至可以将原始行注释在其上方。我知道文档说,“编译器生成对消息传递函数的调用。你永远不应该在你编写的代码中直接调用它。” 你必须独自决定什么时候可以改变规则。

于 2009-12-15T16:32:09.523 回答