1

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

4

2 回答 2

0

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

无论如何,问题在于编译器正在优化测试(它将这解释为测试一个在编译时为真的常量表达式)。您可以通过将此地址读入本地volatile变量来规避此问题。或者您可以在运行时动态搜索符号。

但我会考虑只检查 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 中,这些中的任何一个都应该像你所期望的那样工作。

希望有帮助。

于 2012-11-14T06:00:31.530 回答
-2

只需检查 NSClassFromString 是否可以获取课程。无论如何,objC 都是所有课程:D

于 2012-11-14T21:11:56.843 回答