与Apple一起更新OS X时,最新的XCode 4.4转储旧的(10.6)SDK,我发现自己需要使用10.7 SDK(或者我认为是10.8)并将我的部署目标设置为10.6以保持兼容性。 / p>
我更喜欢链接到较旧的SDK,因为我知道我不能错误地引入对尚不存在的API的调用。当我上次尝试逆向方法时,我发现自己经常做的事情。
我发现自己在做的是使用XCode中的代码完成功能来选择"对"要求像NSWorkspace这样的简单类,那么在开发过程中一切正常,我忘了它,当我发布新版本时:Kaboum!整个应用程序在运行时在早期的OS X版本上爆炸;经常在那些难以到达的地方: - )
或者至少这是几年前我的情况。
当然,现在还有办法:
确保您不会引入部署目标中尚未提供的API调用,即使它们已在SDK中定义
在构建或静态分析时检测此类调用
我确定我错过了某个地方的某些地方..请赐教我!
致以最诚挚的问候,
谢
答案 0 :(得分:8)
当然,现在还有办法:
确保不引入尚未提供的API调用 在您的部署目标中,即使它们已在SDK中定义
在构建或静态分析时检测此类调用
不,没有。是的,你应该打开雷达(bugreport.apple.com)。如果你愿意,你可以欺骗我:rdar://11985733
是的,尽管Apple建议,唯一可行的解决方案是复制旧的SDK并链接它们。
我花了很长时间与Xcode团队讨论WWDC 2012上的这个问题。他们一致认为它已经坏了。目前没有计划修复它。升级雷达是我们如何影响Apple对这些事情的看法。
答案 1 :(得分:2)
我通常将SDK从旧版本复制到较新版本,这样如果我使用不受支持的东西,编译器会惹我生气。
此外,您可以在调用某些您不确定的方法时查看快速帮助,例如在屏幕截图中,您可以看到 launchApplicationAtURL 方法仅适用于10.6
答案 2 :(得分:2)
我在iOS上也遇到了这个恼人的问题。它实际上在iOS上更加烦人,因为用户必须将他们的设备与iTunes同步,并在发送崩溃报告之前启用崩溃报告发送,而不像Mac OS X那样你不需要做所有这些。最近,我设法添加了一个编译时检查,用于检查旧版SDK的API。我将首先解释我是如何首先为iOS做的,然后尝试帮助您在Mac OS X中使用这种技术。我不会为Mac atm编写太多代码,因此我只能从我的经验中指导您正确的方向使用iOS,但是一旦我下班回来,我会在今天晚些时候测试我的建议。
所以这就是我为iOS做的事情:
我首先得到了我想要的旧版模拟器 SDK。我可以通过下载包含所需SDK的旧Xcode 3 (非4)版本轻松获得此功能。
我接下来必须安装SDK。这不是太难,所以我不会在这里解释太多。但SDK存储在Packages
文件夹中。此文件夹在早期的Xcode 3版本中清晰可见,但在更高版本中隐藏。您也可以通过终端轻松打开它。此外,在Xcode 4.3中更改Developer
文件夹移动到Xcode.app之后,所以我必须将SDK安装到tmp文件夹中并自己将SDK移动到Xcode.app中。如果我打开它,我需要重启Xcode。
之后,我在您的项目中复制了我的debug
配置,并将其命名为my 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。如果你不这样做,我认为Apple与iOS有类似的东西,SDK可以在开发中心或互联网上的某个地方下载......
至于设置Base SDK,如果它没有列出,那么我认为名称是MacOSX10.6
或你所追求的任何版本。
其他一切都应该是一样的,但如前所述,我今天晚些时候会测试这个方法并编辑我的答案以给出一个更明确的答案,但我想这个方法适用于Mac SDK。
答案 3 :(得分:2)
我还假设编译器会警告我过于新的&#34;部署目标操作系统版本的API用法。但事实证明,编译器默认情况下不会警告你。其中一个原因可能是您仍然可以通过在运行时使用&#34; respondsToSelector:&#34;检查可用性来使用新API,例如,在较新的操作系统版本上,即使部署目标版本较旧。你需要在Xcode 7.3+上添加编译器选项 -Wpartial-availability (待确认),以获得警告:&#39;部分:在macOS 10.x&#34;中引入警告信息。
在macOS 10.12.3上使用Xcode 8.2.1:
$ 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.
答案 4 :(得分: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
答案 5 :(得分: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/。