在尝试测试是否存在在较新版本的操作系统中引入的符号时,我遇到了一个奇怪的问题。我遵循Apple关于使用弱链接符号的指南,即
通过显式比较其地址(而不是符号的裸名)与 NULL 或 nil 来检查外部(extern)常量或通知名称的可用性。
为了重现该问题,我在最新的 Xcode 4.5.2 上使用最新的 iOS 6 SDK,使用默认编译器(Apple LLVM 编译器 4.1)。我弱链接了社交框架(仅在 iOS 6+ 上可用)。我在 iOS 5.1 上运行这段代码(部署目标低于 6):
NSLog(@"%p", &SLServiceTypeFacebook);
if (&SLServiceTypeFacebook)
NSLog(@"Yes1");
if (&SLServiceTypeFacebook != NULL)
NSLog(@"Yes2");
输出是:
0x0
Yes1
Yes2
换句话说,我们可以在运行时验证表达式&SLServiceTypeFacebook
的计算结果是否为 0。然而,if
测试该表达式的语句将其视为真。
更新: 从这个问题,我发现这个解决方法没有优化,但没有优化:
typeof(&SLServiceTypeFacebook) foo = &SLServiceTypeFacebook;
if (foo)
NSLog(@"Yes3"); // does not get executed on -O0, but does on any optimization
更新: UIKit 符号似乎不存在此问题。在 iOS 4.3 上运行以下命令:
NSLog(@"%p", &UIKeyboardDidChangeFrameNotification);
if (&SLServiceTypeFacebook)
NSLog(@"Yes1");
if (&SLServiceTypeFacebook != NULL)
NSLog(@"Yes2");
输出是:
0x0
我假设不同之处在于 UIKit 符号NS_AVAILABLE_IOS()
旁边有一个宏,因此编译器会以某种方式正确处理它。在社交框架符号的情况下,它没有NS_AVAILABLE_IOS()
宏,因为整个社交框架本身仅在 iOS 6 之后才可用(即符号从框架版本开始可用,所以我猜不需要这个宏?);但是编译器没有正确处理符号。