在尝试测试是否存在在较新版本的操作系统中引入的符号时,我遇到了一个奇怪的问题。我遵循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之后可用(即符号自框架版本以来可用,所以我猜不需要这个宏?);但是编译器没有正确处理符号。
答案 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