如何在 Xcode 6.3 中检查 Facebook 帐户支持?

How to check for Facebook account support in Xcode 6.3?

在我的 Facebook 模型 class 中,我有一个功能来检查用户的 iOS 是否支持 Facebook 帐户管理:

+ (BOOL)canUseExternalNetwork
{
    return &ACAccountTypeIdentifierFacebook != nil;
}

从 Xcode 6.3 开始,编译器报错:

Comparison of address ACAccountTypeIdentifierFacebook not equal to null pointer is always true

首先,我不明白为什么旧的 iOS 上的未定义常量会解析为大于 0 的地址。更重要的是,我想解决这个问题而不用破解:

This has all the hallmarks of a slight misfeature (also known as a bug) in the compiler that it doesn't properly assess -weak_framework when using symbols defined in framework headers as being weakly linked, and as such considers the code a no-op.

这意味着优化器很高兴能够从代码中删除 if 检查 - 当我使用一段简单的测试代码时它确实这样做了。

#import <Accounts/ACAccountType.h>
#import <stdio.h>

int
main(int argc, char **argv)
{
    if (&ACAccountTypeIdentifierFacebook != NULL)
        NSLog(@"Hello\n");
    return (0);
}

此代码编译为:

$ clang -weak_framework Accounts -framework Foundation weak.m
weak.m:8:10: warning: comparison of address of 'ACAccountTypeIdentifierFacebook' not equal to a null pointer is always true [-Wtautological-pointer-compare]
    if (&ACAccountTypeIdentifierFacebook != NULL)
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~    ~~~~
1 warning generated.

检查时,显示代码中甚至没有引用 ACAccountTypeIdentifierFacebook 符号:

$ nm -m a.out
                 (undefined) external _NSLog (from Foundation)
                 (undefined) external ___CFConstantStringClassReference (from CoreFoundation)
0000000100000000 (__TEXT,__text) [referenced dynamically] external __mh_execute_header
0000000100000f40 (__TEXT,__text) external _main
                 (undefined) external dyld_stub_binder (from libSystem)

即优化器将其完全删除。您可以使用 otool -tv a.out 检查结果代码,您会看到 if 测试被完全跳过。

希望它会在编译器的未来版本中得到修复,但是您可以暂时解决该问题。

为了让编译器认为该符号是弱的,它需要显式标记为 weak import,这意味着它需要看起来像:

extern NSString * const ACAccountTypeIdentifierFacebook __attribute__((weak_import));

这意味着代码如下:

if (&ACAccountTypeIdentifierFacebook != NULL) {
    NSLog(@"Have Facebook");
}

然后将正常工作。如果我们在示例代码的开头添加这样一行并编译它,我们会看到它编译没有问题,并且该符号出现在 nm -m a.out 的输出中,并且 if 测试是出现在 otool -tv a.out.

的结果输出中