Swift #pragma clang 诊断的替代方案

Swift alternative for #pragma clang diagnostic

问题

我最近在这段代码中遇到第三方实用程序 (WEPopover) 的警告:

_effectivePopoverContentSize = _contentViewController.contentSizeForViewInPopover;

这会生成以下警告:

warning: 'contentSizeForViewInPopover' is deprecated: first deprecated in iOS 7.0 - Use UIViewController.preferredContentSize instead. [-Wdeprecated-declarations]
            _effectivePopoverContentSize = _contentViewController.contentSizeForViewInPopover;

Objective-C 中对此的一个临时修复是使用 pragma clang 诊断来消除错误(我会让代码作者处理真正的修复)。所以我修改了代码:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
            _effectivePopoverContentSize = _contentViewController.contentSizeForViewInPopover;

#pragma clang diagnostic pop

问题

这很好用,但这让我考虑如果存在任何替代方案,在 Swift 中编码时需要消除类似的误报警告怎么办?

注意事项

我观察到我可以在整个项目范围内停用此类警告(使用 Xcode 设置),但我想考虑如上所述的内联问题。我还考虑过将 #define 添加到我的 Swift 项目中的 .bridging-header.h 文件中,并以某种方式利用它;但是我正在寻找 Swift 解决此问题的具体方法。我确实知道 pragma 不再可用,我搜索了 SO 并发现了类似但不重复的问题。

更新后的决议:Swift 2.0

所提供的答案解决了我对内联警告的担忧。可用性命令应该允许完全避免此类问题,因为在编译时会发出警告。

Apple 的 Swift 书中明确指出:

“You use an availability condition in an if or guard statement to conditionally execute a block of code, depending on whether the APIs you want to use are available at run time. The compiler uses the information from the availability condition when it verifies that the APIs in that “block of code are available.

 if #available(iOS 9, OSX 10.10, *) {
 // Use iOS 9 APIs on iOS, and use OS X v10.10 APIs on OS X 
 } else {
 // Fall back to earlier iOS and OS X APIs 
 }

摘自:Apple Inc.“Swift 编程语言(Swift 2 预发行版)。”电子书。 https://itun.es/us/k5SW7.l

甚至可以使用 guard 语句结合可用性提前退出范围,除非满足可用条件。

guard #available(iOS 8.0, OSX 10.10, *) else { return }

摘自:Apple Inc.“将 Swift 与 Cocoa 和 Objective-C 结合使用(Swift 2 预发布版)。”电子书。 https://itun.es/us/utTW7.l

此外,我对处理宏的相关担忧已解决,如下所述。请记住 Swift 没有预处理器,这些工具似乎是可行的方法。

Simple Macros

Where you typically used the #define directive to define a primitive constant in C and Objective-C, in Swift you use a global constant instead. For example, the constant definition #define FADE_ANIMATION_DURATION 0.35 can be better expressed in Swift with let FADE_ANIMATION_DURATION = 0.35. Because simple constant-like macros map directly to Swift global variables, the compiler automatically imports simple macros defined in C and Objective-C source files.”

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C (Swift 2 Prerelease).” iBooks. https://itun.es/us/utTW7.l

Complex Macros

Complex macros are used in C and Objective-C but have no counterpart in Swift. Complex macros are macros that do not define constants, including parenthesized, function-like macros. You use complex macros in C and Objective-C to avoid type-checking constraints or to avoid retyping large amounts of boilerplate code. However, macros can make debugging and refactoring difficult. In Swift, you can use functions and generics to achieve the same results without any compromises. Therefore, the “complex macros that are in C and Objective-C source files are not made available to your Swift code.”

Excerpt From: Apple Inc. “Using Swift with Cocoa and Objective-C (Swift 2 Prerelease).” iBooks. https://itun.es/us/utTW7.l

API 的开发人员将能够使用以下方法标记 Swift 中功能的可用性:

available(iOS 8.0, OSX 10.10, *)
func useShinyNewFeature() {
    // ...
}

摘自:Apple Inc.“将 Swift 与 Cocoa 和 Objective-C 结合使用(Swift 2 预发布版)。”电子书。 https://itun.es/us/utTW7.l

将这些标记添加到为 Swift 重写的函数中似乎是保持框架向后兼容性的好方法。 guard/available 组合将允许这些框架的用户根据需要调整逻辑。这让我放心地处理在线警告、API 回退和一般的宏。

截至 2.0 版(撰写本文时目前处于测试阶段),Swift 仍然不包含预处理器,并且短期内不会改变(如果有的话)。预处理器允许的有益能力以各种方式内置到语言本身(我不会在这里涵盖所有这些,请参阅文档)并且是编译时级别的功能。

有两个功能我想提一下(一个是旧的,一个是新的),它们可能正是您正在寻找的:

  1. 条件编译 - 如 Using Swift with Cocoa and Objective-C 所述,您可以实现条件编译语句,只允许您编译给定特定操作系统或处理器架构的代码。如果看起来像这样:

  1. 检查 API 可用性 - 如 The Swift Programming Language 所述,您现在可以根据平台检查 API 可用性 OS 版本。这将允许您利用较新的 API,同时允许您处理该功能在较旧(或不同)平台或 OS 上不可用的情况。您可以使用它来替代替代实现或向用户提供解释。如果看起来像这样:

这些工具(以及语言中内置的许多其他工具)应该允许开发人员替换 Objective-C 和 C 预处理器宏。就个人而言,我认为它们是一个巨大的进步。