14

一如既往,当 Apple 更新 OS X 时,最新的 XCode 4.4 转储了旧的 (10.6) SDK,我发现自己需要使用 10.7 SDK(或者我想是 10.8)并将我的部署目标设置为 10.6 以保持兼容性。

我更喜欢链接到较旧的 SDK,因为我知道我不能错误地引入对尚不存在的 API 的调用。当我上次尝试逆向方法时,我发现自己经常做的事情。

我发现自己在做的是,我使用 XCode 中的代码完成功能为像 NSWorkspace 这样的简单类选择“正确”调用,然后在开发过程中一切正常,我忘记了它,当我发布新版本时:Kaboum!整个应用程序在运行时在早期的 OS X 版本上爆炸;经常在那些难以到达的地方:-)

或者至少这是我几年前的情况。

当然,现在有一种方法可以:

  • 确保不引入部署目标中尚不可用的 API 调用,即使它们已在 SDK 中定义

  • 在构建或静态分析期间检测此类调用

我确定我错过了一些东西,沿线某处..请赐教!

最好的祝福,

坦率

4

6 回答 6

8

当然,现在有一种方法可以:

  • 确保不引入部署目标中尚不可用的 API 调用,即使它们已在 SDK 中定义

  • 在构建或静态分析期间检测此类调用

不,那里没有。是的,您应该针对它打开一个雷达 (bugreport.apple.com)。如果你喜欢,你可以欺骗我的:rdar://11985733

是的,尽管 Apple 建议,唯一可行的解​​决方案是复制旧的 SDK 并链接它们。

我在 WWDC 2012 上花了很长时间与 Xcode 团队讨论这个问题。他们同意它已经坏了。目前没有修复它的计划。不断升级的雷达是我们在这些事情上影响苹果的方式。

于 2012-07-30T14:22:36.013 回答
2

我通常将 SDK 从旧版本复制到新版本,这样如果我使用不支持的东西,编译器就会责备我。

您也可以在调用一些您不确定的方法时简单地查看快速帮助,例如在屏幕截图中您可以看到launchApplicationAtURL方法仅适用于 10.6

在此处输入图像描述

于 2012-07-30T14:07:43.167 回答
2

我在 iOS 上也遇到过这个烦人的问题。在 iOS 上实际上更烦人,因为用户必须在发送崩溃报告之前将他们的设备与 iTunes 同步并启用崩溃报告发送,这与 Mac OS X 不同的是,您不需要做所有这些。最近,我设法添加了一个编译时检查,用于检查 API 与旧版本的 SDK。我将首先解释我是如何在 iOS 上做到这一点的,然后尝试帮助你在 Mac OS X 上适应这种技术。我没有为 Mac atm 编写太多代码,所以我只能根据我的经验真正引导你朝着正确的方向前进使用 iOS,但我将在今天晚些时候测试我的建议,一旦我下班并给出明确的答案。


所以这就是我为 iOS 所做的:

我首先必须获得我想要获得的旧版Simulator SDK。我可以通过下载包含所需 SDK的旧 Xcode 3 (不是 4)版本轻松获得此功能。

接下来我必须安装 SDK。这不是太难,所以我不会在这里解释太多。但是 SDK 存储在Packages文件夹中。此文件夹在早期 Xcode 3 版本中清晰可见,但在更高版本中隐藏。无论如何,您都可以通过终端轻松打开它。此外,在 Xcode 4.3 中Developer文件夹移动到 Xcode.app 中的更改之后,我不得不将 SDK 安装到 tmp 文件夹中,然后自己将 SDK 移动到 Xcode.app 中。如果我打开它,我将需要重新启动 Xcode。

之后,我debug在您的项目中复制了我的配置并将其命名,在我的情况下,类似iOS 4.3 API Check或类似的东西 - 并不重要。然后我将这个新配置的 Base SDK 更改为我安装的旧 SDK。虽然我安装的 SDK 没有列出,所以我不得不other再次选择并输入iphonesimulator4.3.

最后,当我需要检查旧版本的 SDK 时,我将Run <appname>.app项目方案中的配置更改为我的iOS 4.3 API Check配置。我们开始了,针对 iOS 4.3 的编译时检查。


至于 Mac OS X,我相信你可以用同样的方法达到同样的目标。Mac SDK 没有模拟器,所以我认为常规的 SDK 可以解决这个问题。至于获取旧版 SDK,如果您仍然安装了 Xcode 4.2(在 Xcode 4.3 更改它之后,该Developer文件夹位于 Xcode.app 中),那么您应该在那里找到 10.6 SDK。如果你不这样做,我想苹果有一个与 iOS 类似的东西,可以在开发中心或互联网上的某个地方下载 SDK ......

至于设置 Base SDK,如果它没有列出,那么我认为它的名称是MacOSX10.6或者你所追求的任何版本。

其他一切都应该相同,但如前所述,我将在今天晚些时候测试此方法并编辑我的答案以给出更明确的答案,但我想这种方法适用于 Mac SDK。

于 2012-07-31T09:42:09.590 回答
2

我还假设编译器会警告我有关部署目标操作系统版本的“太新”API 使用情况。但事实证明,编译器默认情况下不会警告你。原因之一可能是您仍然可以通过在运行时使用“respondsToSelector:”检查可用性来使用新 API,例如,即使部署目标版本较旧,也可以在较新的操作系统版本上使用。您需要添加 Xcode 7.3+ 上可用的编译器选项-Wpartial-availability(待确认),以获得“警告:'某些东西'是部分的:在 macOS 10.x 中引入”警告消息。

在带有 Xcode 8.2.1 的 macOS 10.12.3 上:

$ cat foo.m
#include <Foundation/Foundation.h>

BOOL foo()
{
    return [@"foo" containsString:@"bar"];
}

$ cc -mmacosx-version-min=10.9 -Wpartial-availability foo.m -c -o foo.o
foo.m:5:20: warning: 'containsString:' is partial: introduced in macOS 10.10 [-Wpartial-availability]
    return [@"foo" containsString:@"bar"];
                   ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSString.h:132:1: note: 
      'containsString:' has been explicitly marked partial here
- (BOOL)containsString:(NSString *)str NS_AVAILABLE(10_10, 8_0);
^
foo.m:5:20: note: explicitly redeclare 'containsString:' to silence this warning
    return [@"foo" containsString:@"bar"];
                   ^
1 warning generated.

另请参阅:XCode 有没有办法警告新的 API 调用?

于 2017-03-22T19:08:48.683 回答
0

我通过修改 Availability.h 来检查我的代码,以使编译器将弱链接符号标记为警告/错误。在我当前的 (Xcode 5/llvm) 化身中,我使用下面的代码。每当我使用 iOS 6.0 或更高版本中引入的符号时,它都会发出警告。我认为这是不言自明的。宏似乎需要在每次 SDK 更新时进行更新,因此请谨慎行事。哦,你也放弃了弃用警告,所以我只偶尔使用它来仔细检查我的条件代码。

#undef __NSi_6_0
#define __NSi_6_0 deprecated=1.0
#undef __NSi_6_1
#define __NSi_6_1 deprecated=1.0
#undef __NSi_7_0
#define __NSi_7_0 deprecated=1.0

#undef __NSd_6_0
#define __NSd_6_0
#undef __NSd_6_1
#define __NSd_6_1
#undef __NSd_7_0
#define  __NSd_7_0

另请参阅http://iphone.m20.nl/wp/2013/10/xcode-5-and-flagging-weak-linked-unavailable-symbols-from-a-newer-sdk/

于 2013-10-24T13:40:37.420 回答
0

由于 Xcode 9 有一个构建设置可以做到这一点,打开警告-Wunguarded-availability和/或-Wunguarded-availability-new.

当使用比部署目标更新的 API 时,前者会发出警告。后者仅在以类似方式使用比 macOS 10.13 或 iOS 11 更新的 API 时发出警告。

对于现有项目,前者默认关闭,后者默认开启。

此设置在 Xcode 的构建设置窗格中称为“无保护可用性”,您可以从 GUI 中选择是、是所有版本或否。

有关更多详细信息,请参阅 WWDC17 会议 411,“LLVM 中的新功能”,https://developer.apple.com/videos/play/wwdc2017/411/

于 2018-09-06T15:14:30.420 回答