【发布时间】:2012-11-02 13:22:21
【问题描述】:
在尝试测试是否存在在较新版本的操作系统中引入的符号时,我遇到了一个奇怪的问题。我按照Apple guidelines 使用弱链接符号,即
检查外部(extern)常量或 通知名称通过显式比较其地址——而不是 符号的裸名——为 NULL 或 nil。
为了重现该问题,我在最新的 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 语句将其视为真。
更新: 从this question,我发现这种解决方法在没有优化的情况下有效,但在优化时无效:
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() 宏,因此编译器会以某种方式正确处理它。在 Social 框架符号的情况下,它没有 NS_AVAILABLE_IOS() 宏,因为整个 Social 框架本身仅在 iOS 6 之后才可用(即,该符号从框架版本开始可用,所以我猜不要'不需要这个宏?);但是编译器没有正确处理符号。
【问题讨论】:
-
第一行不应该是
NSLog(@"%p", SLServiceTypeFacebook),其中SLServiceTypeFacebook是一个指针吗? -
@RoboticCat:不,不可用的弱链接符号的地址为0,尝试访问该符号会导致段错误。
-
好的 - 最后的想法(然后我没有想法) -
NSLog(@"%x", &SLServiceTypeFacebook);怎么样? -
@RoboticCat 这不应该有任何区别,因为它只是以不同的格式打印,传递的值将是相同的。
-
@JustSid:它们应该返回不同的值(注意第一条评论中的
&与第二条评论中的&)。无论如何,这只是一个想法。
标签: iphone objective-c ios xcode weak-linking