【问题标题】:Negating Objective-C's @available keyword否定 Objective-C 的 @available 关键字
【发布时间】:2018-03-05 10:28:27
【问题描述】:

我只想在当前设备的 iOS 版本低于特定版本时运行一段代码,如指定的 here。苹果给出的代码示例如下:

if (@available(iOS 10.0, *)) {
  // iOS 10.0 and above
} else {
  // below 10.0
}

但是,在某些情况下,仅当当前 iOS 版本低于特定版本时才希望运行代码。我假设以下代码可以工作:

if (!@available(iOS 10.0, *)) {
  // below 10.0
}

但是这似乎不起作用,我从 Xcode 收到以下警告:

@available does not guard availability here; use if (@available) instead

Here 是添加了我看到的诊断的 LLVM 提交。

该问题有两种可能的后备方案:

  1. 使用if-else 变体而不向if 块添加任何代码(不是很优雅)。
  2. 继续使用旧方法,例如-[NSProcessInfo isOperatingSystemAtLeastVersion:]

还有其他我想念的使用 @available 的方法吗?

【问题讨论】:

  • 我已阅读 LLVM 文章,它指出您不能在 if 中将@available 与任何其他条件或指令一起使用。所以基本上我能想到的唯一方法是拥有一个空的if 正文,但在else 块内执行操作。这对我来说似乎是唯一可能的方法。
  • "但是这似乎不起作用,我从 Xcode 收到以下警告:" 仅仅因为有警告并不意味着它不起作用。警告说它不保护可用性,但您只是将它用作版本检查,而不是保护可用性。

标签: ios objective-c ios11 xcode9 availability


【解决方案1】:

@available 的想法是您希望使用仅在某些系统上可用的 API。对于其他系统,您的应用程序中缺少该功能,或者您提供了替代功能。在您不需要超出某个操作系统版本的任何代码的情况下,正确的使用方法是

if (@available(iOS 10.0, *)) {
    // Happens automatically on on iOS 10 and beyond
} else {
    someOtherCode();
}

原因是编译器有时必须对@available 保护的代码执行一些额外的魔法,因此它需要清楚地识别出这种情况。所以实际上它明确搜索

if (@available(...)) {

只允许空格和换行的变化。是的,你可能会说一个 not (!) 真的一点也不复杂,但是你会在哪里画线呢?怎么样:

if ((todayIsTuesday() && @available(iOS 9.0, *)) 
    || (self.theWeatherIsNice && !@available(iOS 11.0, *)) {

因此只允许一个简单的语句,它只强制编译器将代码分成两个部分,并且总是只有一个部分可以肯定运行:一个用于列出的操作系统,一个用于其余部分。当然,“剩下的”可以再细分,else if是允许的。如果缺少,只有 else 部分可以自动生成,所以当你写这个时:

if (@available(...)) {
    someCode();
} // There is no else

编译器也很高兴,因为那是一样的

if (@available(...)) {
     someCode();
} else {
    // Nothing to do here
}

【讨论】:

  • 接受详细的答案。我同意你的推理,尽管我认为这种否定的特殊情况值得特别处理。
  • @StatusReport 也许您应该向 clang 提交增强请求,但不是在 Apple 的门户上,而是直接在 LLVM 门户上。要么他们会实施它,要么他们会提供一个很好的理由说明他们不希望或技术上不能以这种方式实施它。 LLVM 开发人员似乎非常被动,之前也曾在那里提交过问题,并且都得到了修复。
【解决方案2】:

您可以定义自己的自定义宏,以便在整个应用程序中使用。示例:-

#define isIOS11() ([[UIDevice currentDevice].systemVersion doubleValue]>= 11.0 && [[UIDevice currentDevice].systemVersion doubleValue] < 12.0)

#define SinceIOS9_2 ([[UIDevice currentDevice].systemVersion doubleValue]>= 4.2 && [[UIDevice currentDevice].systemVersion doubleValue] < 9.2)

像下面这样使用它:-

if (isIOS11()) {
    // Do something for iOS 11 
} else {
    // Do something iOS Versions below 11.0
}

如果这对你有用,请告诉我。

【讨论】:

  • 这很整洁。我想我有一天会试试那个。谢谢!
  • 这不会抑制 Xcode 9 中新的“Unguarded Availability”警告。
【解决方案3】:
if (@available ...) {
   ...
} else {
   ...
}

是唯一允许的形式。它必须是这样的,因为不同的规则适用于 if-part 和 else-part。在 if 部分中,您可以调用一个 SDK 中可用的方法,在 else 部分中,它是来自另一个 SDK 的方法。同一个调用在一个分支中是合法的,而在另一个分支中是非法的,或者在一个分支中被弃用而不在另一个分支中被弃用。

【讨论】:

    猜你喜欢
    • 2023-03-04
    • 1970-01-01
    • 2012-12-01
    • 1970-01-01
    • 2010-12-31
    • 2012-08-18
    • 1970-01-01
    • 2018-04-08
    • 1970-01-01
    相关资源
    最近更新 更多