OS の新しいバージョンで導入されたシンボルの存在をテストしようとすると、奇妙な問題が発生します。弱リンクシンボルの使用に関するAppleのガイドラインに従います。
外部 (extern) 定数または通知名の可用性を、そのアドレス (シンボルの生の名前ではなく) を NULL または nil と明示的に比較することによって確認します。
この問題を再現するために、デフォルトのコンパイラ (Apple LLVM コンパイラ 4.1) を使用して、最新の Xcode 4.5.2 で最新の iOS 6 SDK を使用しています。Social フレームワーク (iOS 6 以降でのみ使用可能) を弱リンクしました。そして、このコードを iOS 5.1 で実行します (展開ターゲットは 6 未満です)。
NSLog(@"%p", &SLServiceTypeFacebook);
if (&SLServiceTypeFacebook)
NSLog(@"Yes1");
if (&SLServiceTypeFacebook != NULL)
NSLog(@"Yes2");
出力は次のとおりです。
0x0
Yes1
Yes2
つまり、式&SLServiceTypeFacebook
が値 0 に評価されることを実行時に検証できます。ただし、if
この式をテストするステートメントは、それが true であるかのように扱います。
更新:この質問 から、この回避策は最適化なしでは機能しますが、最適化では機能しないことがわかりました。
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 以降でしか利用できないため、マクロはありません (つまり、シンボルはフレームワークのバージョン以降で利用できるので、これは必要ないと思います)。大きい?); しかし、コンパイラはシンボルを正しく処理しません。