在iOS中测试弱链接符号无法按预期工作

时间:2012-11-14 02:29:23

标签: iphone objective-c ios xcode weak-linking

在尝试测试是否存在在较新版本的操作系统中引入的符号时,我遇到了一个奇怪的问题。我遵循Apple guidelines使用弱链接符号,即

  

检查外部(外部)常数或a的可用性   通知名称通过显式比较其地址而不是   符号的裸名称 - 为NULL或nil。

要重现此问题,我使用默认编译器(Apple LLVM编译器4.1)在最新的Xcode 4.5.2上使用最新的iOS 6 SDK。我弱化了社交框架(仅适用于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()宏,因此编译器会以某种方式正确处理它。在社交框架符号的情况下,它没有NS_AVAILABLE_IOS()宏,因为整个社交框架本身仅在iOS 6之后可用(即符号自框架版本以来可用,所以我猜不需要这个宏?);但是编译器没有正确处理符号。

2 个答案:

答案 0 :(得分:0)

您确定不想检查SLRequest类是否存在而不是检查此常量吗?

在任何情况下,问题都在于编译器正在优化测试(它将其解释为测试在编译时为真的常量表达式)。您可以通过将此地址读入本地易失性变量来避免这种情况。或者您可以在运行时动态搜索符号。

但我会考虑只是检查SLRequest类。

以下是至少这三个选项:

#include <dlfcn.h>

NSString* const * volatile check = &SLServiceTypeFacebook;
if (check != NULL)
    NSLog(@"SLServiceTypeFacebook is defined");

// Another approach would be to call dlsym() at runtime 
// to search for this symbol:
if (dlsym(RTLD_DEFAULT, "SLServiceTypeFacebook"))
    NSLog(@"SLServiceTypeFacebook found via dlsym");

// But if you really just wanted to know is if SLRequest
// is available, you should really just do this:
if ([SLRequest class])
    NSLog(@"SLRequest class is available");

任何这些都应该像你在iOS5.1和iOS6中所期望的那样工作。

希望有所帮助。

答案 1 :(得分:-2)

如果你能获得类,只需检查NSClassFromString .. objC无论如何都是类:D