1

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 以降でしか利用できないため、マクロはありません (つまり、シンボルはフレームワークのバージョン以降で利用できるので、これは必要ないと思います)。大きい?); しかし、コンパイラはシンボルを正しく処理しません。

4

2 に答える 2

0

この定数を確認する代わりに、SLRequest クラスが存在することを確認したくないですか?

いずれにせよ、問題は、コンパイラがテストを最適化していないことです (これは、コンパイル時に true である定数式をテストしていると解釈されます)。このアドレスをローカルの揮発性変数に読み込むことで、これを回避できます。または、実行時にシンボルを動的に検索することもできます。

しかし、代わりに SLRequest クラスをチェックすることを検討します。

少なくとも次の 3 つのオプションがあります。

#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 に答える