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

Why does objective-c not have API availability checking?

Swift 2 个 API availability checking.

The compiler will give you an error when using an API too new for your minimum target OS

为什么 objective-c 编译器不能做同样的事情?

我用谷歌搜索 objective c API 可用性检查,结果只有 swift 2 个结果,所以我认为 objective c 的编译器无法做到这一点。

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

将 Objective-C 代码链接到太旧的 SDK 时会出错。这仅仅是因为使用的方法或 class 或 $whatever 未在该 SDK 的 header 中定义。再次,当然。

这是典型的 Swift Apple 营销:由于 Swift 的无能,他们必须扩展语言才能得到一些东西,这在 Objective-C 中很容易。他们没有澄清这是 Swift 的劣势造成的结果,而是告诉你这是 Swift 的一大特点。这就像割伤你的手指然后说:"We have the great plaster feature!!!!!!!!" 你只需要等几天,然后就会出现一个问题:"Why does Objective-C does not have the great plaster feature???????" 简单的答案:它不会割伤你的手指。

问题是没有产生错误。问题是所有版本都有一个源代码,因此您可以简单地更改 SDK 版本并获得新代码(或错误)。您需要它以便于维护。

在 Objective-C 中,您只需使用此处找到的答案即可: Conditionally Hide Code from the Compiler 或者您可以按照 Q 的评论中提到的那样在运行时执行此操作。(但这本质上是问题的不同解决方案,因为它是一种动态方法,而不是您必须在Swift.)

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

警告(Swift 使其成为一个错误)多年来一直没有在 Clang 编译器中实现,但这并不是固有的 Objective-C 限制(尽管由于其动态特性,您将无法掌握所有情况),也无法掌握 Swift 术语。

使用可用性信息注释 headers 的 Apple 宏(例如 NS_CLASS_AVAILABLE)和源属性(__attribute__((visibility(...)))__attribute__((availability(...))))已经存在多年,并且它们在 Apple 的 SDK 中是 widely-used。宏在 FoundationNSObjCRuntime.hAvailability.h/AvailabilityMacros.h 系统 headers 中定义,编译器可以(并且确实)读取它们。

2015 年初,-Wpartial-availability 警告 has been added 到 Clang 的 master 分支,但是这个 commit/warning 直到 (包括)Xcode 7.2。在 Xcode 7.2 中向项目添加警告标志时,您将获得一个 unknown warning option 日志,但该标志在 Xcode 7.3 中可用。目前没有针对它的预定义设置,但您可以将标志添加到 Build Settings.

下的 Other Warning Flags

还有其他工具使用 LLVM 库来检测部分可用的 API,例如 Deploymate. For my diploma thesis, I developed a tool that integrates directly into Xcode and is based on a modification to the Clang compiler. The code is still online,但我没有跟上一般的 Clang 开发,所以它不会有太大用处,除了用于学习目的。但是,"official" 代码(上面链接)更清晰、更好。

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

Objective C 没有 可用性检查 作为语言的一部分,因为通过 Objective C 预处理器可以获得相同的结果。 这是 C 派生语言中的 "traditional" 方法。

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

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

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

此文件位于 /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:(后者在 class 级别)。

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

Objective C 方法存在验证,例如在 class 级别:

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函数是否存在,那就更简单了:如果存在,那么这个函数本身就不为空。

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

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

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

对于调用比您的部署目标更新的 API(如果这些调用未包装在支票中),这会发出警告。

终于 ;)

最近确实如此。此外,使用 Xcode 11(包括当前的 Xcode 11.3.1),您甚至可以从代码片段中获取它。按 Xcode 右上角的 + 按钮(如下图所示)。

然后在搜索框中输入 "API"。 API 可用性检查代码段的所有 3 个版本都会出现 -- Objective C、C 和 Swift。