为什么objective-c没有API可用性检查?

时间:2015-12-01 05:32:13

标签: objective-c llvm-clang

Swift 2有API availability checking

  

当使用对您来说太新的API时,编译器会给您一个错误   最低目标操作系统

为什么objective-c编译器不能做等效的?

我搜索了目标c API可用性检查,只有swift 2结果出来,所以我假设目标c的编译器不能这样做。

5 个答案:

答案 0 :(得分:44)

Xcode 9.0将运行时可用性检查语法从Swift带到Objective-C:

if (@available(macOS 10.9, *))
{
// call 10.9+ API
}
else
{
// fallback code
}

这有完整的警告,用于调用比部署目标更新的API(如果这些调用未包含在检查中)。

最后;)

答案 1 :(得分:20)

警告(Swift使其成为错误)多年来一直没有在Clang编译器中实现,但它不是固有的Objective-C限制(尽管由于它的动态特性,你赢了& #39;能够捕捉所有案例),也不能赶上Swift术语。

用于注释带有可用性信息的标头的Apple宏(例如,NS_CLASS_AVAILABLE)和源属性(__attribute__((visibility(...)))__attribute__((availability(...))))已存在多年,并广泛用于Apple的SDK。这些宏在Foundation' NSObjCRuntime.hAvailability.h / AvailabilityMacros.h系统标头中定义,编译器可以(并且确实)读取它们。

2015年初,对{@}} -Wpartial-availability分支master警告has been added,但此提交/警告未进入Apple'版本的Clang直到(包括)Xcode 7.2。在Xcode 7.2中向项目添加警告标志时,您将获得unknown warning option日志,但该标志在Xcode 7.3中可用。目前没有预定义设置,但您可以在构建设置下将标记添加到Other Warning Flags

还有其他工具使用LLVM库来检测部分可用的API,例如Deploymate。对于我的毕业论文,我开发了一个直接集成到Xcode中的工具,它基于对Clang编译器的修改。代码仍然是online,但我还没有跟上Clang的一般开发,因此除了学习目的外,它不会有多大用处。然而,"官方"代码(上面链接的)更清洁,更好。

编辑:从Xcode 9开始,可用性检查也适用于Objective-C(和C)。而不是使用上述警告标志,它不支持临时/本地提升部署目标,因此导致大量误报,而-Wunguarded-availabilityif (@available(iOS 11, *)) {...}检查和提升以下代码块的部署目标。它默认是关闭的,但默认情况下会-Wunguarded-availability-new处于启用状态,并开始检查iOS / tvOS 11,watchOS 4和High Sierra之外的任何内容。有关详细信息,请参阅Xcode 9 beta release notes,目前需要使用开发者帐户登录。

答案 2 :(得分:3)

目标C没有可用性检查作为语言的一部分,因为可以通过Objective C预处理器获得相同的结果。 这就是"传统"用C语言编写的方法。

想知道是否在调试模式下编译?

#ifdef DEBUG
  // code which will be inserted only if compiled in debug mode
#endif 

想在编译时检查最低版本吗? 使用iOS中的Availability.h标头和Mac OS X的类似标头。

此文件位于/ usr / include目录中。

只需使用预处理器测试__IPHONE_OS_VERSION_MAX_ALLOWED,例如:

#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
            if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
                [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil]];
            }else{
                [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
            }
#else
            [[UIApplication sharedApplication] registerUserNotificationSettings: (UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert)];
#endif

由于Swift没有预处理器,他们必须发明一种在语言本身内进行这种检查的方法。

如果要在运行时检查方法的可用性,请注意适当的方法是使用方法 respondsToSelector:,或 instancesRespondToSelector:(后者在班级)。

您通常希望将两种方法结合起来,编译时条件编译和运行时检查。

目标C方法存在验证,例如在班级:

if ([UIImagePickerController instancesRespondToSelector:
              @selector (availableCaptureModesForCameraDevice:)]) {
    // Method is available for use.
    // Your code can check if video capture is available and,
    // if it is, offer that option.
} else {
    // Method is not available.
    // Alternate code to use only still image capture.
}

如果你想测试运行时是否存在C函数,它甚至更简单:如果存在,函数本身就不是null。

您无法在两种语言中使用相同的相同方法。

答案 3 :(得分:1)

这几天来。此外,使用Xcode 11(包括当前的Xcode 11.3.1),您甚至可以从代码片段中获取它。按Xcode右上方的+按钮(如下图所示)。 enter image description here

然后在搜索框中,键入“ API”。将显示API可用性检查的代码段的所有3个版本-目标C,C和Swift。 enter image description here

答案 4 :(得分:-3)

当然,您将在Objective-C代码中遇到错误。但是如果你使用为Swift定义的术语,你将不会在Google中找到Objective-C的结果,因为如果你搜索德语单词,你将无法在google中找到kisuaheli网站。 ; - )

将Objective-C代码与过旧的SDK相关联时会出错。这只是因为使用的方法或类或$ SDK的标头中没有定义。当然,再次。

这是Apple的典型Swift营销:因为Swift无法扩展语言以获得某些东西,这在Objective-C中非常容易。他们告诉你这是Swift的一个很棒的功能,而不是澄清这是Swift的不良结果。这就像割你的手指然后说:“我们有很棒的石膏功能!!!!!!!!”你只需要等待几天,然后就可以通过问:“为什么Objective-C没有伟大的石膏功能?”简单的答案:它不会割伤你的手指。

问题是生成错误。问题是为所有版本提供一个源代码,因此您只需更改SDK版本并获取新代码(或错误)。您需要这样才能更容易维护。

在Objective-C中你可以使用这里找到的答案: Conditionally Hide Code from the Compiler或者您可以在运行时按照Q的注释中的说明执行此操作。(但这本质上是问题的不同解决方案,因为它是一种动态方法而不是静态方法,因为您必须在迅速的。)

在Swift中使用语言功能的原因是Swift没有预处理器,所以Objective-C解决方案在Swift中不起作用。因此,Swift中的条件代码是不可能的,他们必须添加石膏,呃,语言功能。