本質的には、ARCで次のコードを変換する良い方法がないためです。
CGColorRef a = ...;
id b = [(id)a autorelease];
CGColorRef c = (CGColorRef)b;
// do stuff with c
コンバーターは-autorelease
いくつかのブリッジキャストを削除して追加しますが、スタックします:
CGColorRef a = ...;
id b = (__bridge_transfer id)a;
CGColorRef c = (__bridge_SOMETHING CGColorRef)b;
// do stuff with c. Except the compiler sees that b is no longer being used!
しかし、移民は何のために何を選ぶべき__bridge_SOMETHING
でしょうか?
- を選択した場合、コンパイラはすぐに解放できるように
__bridge
、b
は使用されなくなります。これはクラッシュします。
- を選択する
__bridge_retained
と、所有権は「CF-land」に戻されますが、元のコードでは、オブジェクトが自動解放プールによって所有されると想定されていました。コードがリークするようになりました。
問題は、ARCが呼び出しを禁止して-autorelease
いるが、オブジェクトが自動解放プールに追加されることを保証する文書化されたメソッドがないことです。これを行う唯一の理由は、自動解放されたCFタイプをメソッドから返すためですが、多くのUIKitクラスにはCFがあります。 -型付きプロパティ(および自動解放された値を返す必要MKOverlayPathView
があるアトミック CGPathRef
プロパティがあります)。
これは、私が本当に文書化したいと思っているARCのトリッキーな部分の1つです。
さまざまな成功の度合いで機能する可能性のある、ジャンプできるフープがいくつかあります。不快感を増すために:
CFAutorelease()
ARCなしでコンパイルされたファイルで関数を定義します(-fno-objc-arc
ターゲット設定→ビルドフェーズ→コンパイルソースのコンパイラフラグに追加します)。これは読者の練習問題として残しておきます。これは、ARCコードがMRCコードと相互運用する必要があるために機能します。これはおそらく最もクリーンなソリューションです。(これは、CFプレフィックスを使用すべきではないというコメントを引き付けることになりますが、リンクエラーが表示されない限り、「2レベルの名前空間」が導入されているため、Cシンボル名の衝突は一般的に安全です。 10.3かそこらで。)
-autorelease
メッセージまたは同等のものを送信するためのさまざまなフープ。これらはすべて、「だましている」ARCに依存しているため、少し厄介です。ただし、最後のid
ABIとの互換性があると想定しているものを除きvoid*
ます。また、クラス/セレクターを検索する必要があるため、おそらく上記よりも低速です(高速objc_lookUpClass()
でsel_registerName()
あるか、最適化されている可能性もありますが、私はそれには賭けません)。
return (__bridge CGColorRef)[(__bridge id)theColor performSelector:NSSelectorFromString(@"autorelease")]
[NSClassFromString(@"NSAutoreleasePool") addObject:(__bridge id)theColor]
return theColor;
return (__bridge CGColorRef)((id(*)(id,SEL))objc_msgSend)((__bridge id)theColor,NSSelectorFromString(@"autorelease"));
return ((void*(*)(void*,SEL))objc_msgSend)(theColor,NSSelectorFromString(@"autorelease"));
__autoreleasing
コンパイラーが最適化できない変数に割り当てることにより、自動解放プールに追加するように強制します。これが保証されているかどうかはわかりません(特に、似たようなものobjc_autoreleaseReturnValue()
がobjc_retainAutoreleasedReturnValue()
可能かもしれませんが、の一般的なケースが遅くなるため、これはありそうもないと思います(NSError * __autoreleasing *)error
)。
-(id)forceAutorelease:(id)o into:(id __autoreleasing*)p
{
*p = o;
return p;
}
-(CGColorRef)CGColor
{
...
CGColorRef theColor = CGColorCreate(...);
CGColorSpaceRelease(space);
id __autoreleasing temp;
return (__bridge CGColorRef)[self forceAutorelease:(__bridge_transfer id)theColor into:&temp];
}
(コンパイラー/ランタイムが協力して、関連するメソッドがオーバーライドされるまで静的ディスパッチ/インライン化を使用することも可能かもしれませんが、それはトリッキーであり、それ自体に大きなオーバーヘッドがないわけではありません。)
を使用typedef
し__attribute__((NSObject))
ます。これは、 ARC仕様の中で最も紛らわしい文書化された部分ですが、次のようなものが機能しているようです。
typedef CGColorRef MyCGColorRef __attribute__((NSObject));
-(MyCGColorRef)CGColor
{
...
return (__bridge MyCGColorRef)(__bridge_transfer id)theColor;
}
これを機能させるには、2つのブリッジが必要だと思います(1つはARCに所有権を譲渡し、もう1つはに所有権を譲渡します)。あなたが単にreturn theColor;
それが漏れているのではないかと思うなら。私がドキュメントを読んだ(__bridge_transfer MyCGColorRef)
ところ、非ARCポインター(CGColorRef)からARCポインター(MyCGColorRef)に変換されているため、必要なだけですが、コンパイラーは文句を言います。__attribute__((NSObject))
残念ながら、ドキュメントにはtypedefの使用方法の例は示されていません。
ヘッダーの戻りタイプを変更する必要はないことに注意してください。そうすることで、自動リリースされた戻り値の最適化が有効になる場合がありますが、コンパイラがMyCGColorRefからCGColorRefへの変換をどのように処理するかはわかりません。ルため息。