2013-03-07 4 views
5

を使用しようとしている間に橋が、私はちょうどshadowPathプロパティのCABasicAnimationを設定して、これは私は好奇心作ら必要な、一貫性のない警告をキャスト:CGPathRef

shadowAnimation.toValue = (id)newShadowPath.CGPath; 

[注意:shadowAnimationはCABasicAnimationオブジェクトであり、newShadowPathUIBezierPathですオブジェクト]

これは動作し、エラー/警告はXcodeに表示されません。しかし、私はそのようにのように書いた場合:

CGPathRef test = newShadowPath.CGPath; 
shadowAnimation.toValue = (id)test; 

をこれは、この警告メッセージを投げて、コンパイルされません。

shadowAnimation.toValue = (__bridge id)test; 

Cast of C pointer type 'CGPathRef' (aka 'const struct CGPath *') to Objective-C pointer type 'id' requires a bridged cast 

だから、それは次のようにそれを入力するために私を必要としなぜこれはそうですか? (id)newShadowPath.CGPathのみを使用すると、最初の例で同じエラーが発生します。 ? __bridgeをXcodeに関係なく配置しても問題は検出されません。または、私はここで何が違うのですか?

答えて

2

違いの理由は、clang 3.1で導入された新しい(やや複雑な)変換ルールにあります。

まず、それを煮詰めることができます:

@@interface Foo : NSObject 
+ (CGPathRef)bar; 
@end 

CGPathRef foo(); 

void test() 
{ 
    // works without bridged cast: 
    id a = (id)[Foo bar]; 

    // needs bridged cast 
    id b = (__bridge id)foo(); 
} 

メッセージの結果をキャストする場合、通常の関数呼び出しは、それを必要としながら、だから我々はbrdgeキャストを省略することができます。それは奇妙に思える。

違いがあるのは、ARCが関数とメソッド名を解釈し、いわゆるC retainable pointer types(Core Foundationオブジェクト)の保持カウントに関する仮定を引き出すためです。

あなたが不一致の理由を見つけることができますARCガイド(「既知のセマンティクスを持つ式の保持可能オブジェクトポインタ型への変換」)の section 3.3.2

式が、それならば保持されないを知らですC 保持可能なポインタ型の右辺値であり、[...]メッセージ送信[...]]

キャスト・オペランドが__bridgeが

キャストとして [...] 変換は同じセクションで説明する理由このない処理され保持されないを知られている場合

C関数に適用され、clangが同様の前提を立てるように装飾する方法を示します。だから我々は、同様に、Cの関数呼び出しのためのブリッジキャストを取り除くために、上からの例を変更することができます。

CGPathRef foo() __attribute__((cf_returns_not_retained)); 

をあなたの最後の質問に答えるために:それは両方の場所に橋のキャストを使用しても安全です。それは、ARCが正しく__bridgeキャストを選択するようにします(メソッドの名前に応じて__bridge_transferキャストが選択される可能性がありますが、この場合は__bridgeが使用されます)。

+0

うわー、これを分析するような努力に行ってくれてありがとう。私は正しい答えとしてこれを受け入れました。何が起きているのかを正確に説明するには、この長い時間がかかります。 –

2

これはARCと、割り当てが行われたときの魔法のために発生します。

CGPathRef testという一時変数を作成して割り当てると、ARCは、標準のメモリパラダイムに従わないCoreBlankインスタンスを使用していることを認識し、保持したり、何も気にしません。

この非管理インスタンスを保持されたidタイプのプロパティに割り当てようとすると、そのインスタンスのメモリを管理する必要がないと考えられたため、LLVMが正しく機能しませんが、今すぐ開始する必要があります(これは__bridgeキーワードの意図です)。

最初のコードスニペットでは、ARCがそのインスタンスをARCで管理する必要があり、ARCで管理されていない参照が存在しないことが常にわかっているため、その理由がわかります。

+0

この説明がどのように明確になるかわかりません。なぜ、 'id =(id)[UIBezierPath new];'は動作しますが、 'id b =(__bridge id)CGPathCreateCopy(NULL);'はブリッジキャストを必要としますか? –

+2

@NikolaiRuhe 'UIBezierPath'はARCが管理するクラスです.CポインタではないのでObjective-Cポインタです。 'CGPathCreateCopy'はC構造体ポインタを返します。これはARCがブリッジされない限り管理しません。 –

+0

混乱して申し訳ありません:私はid id =(id)[UIBezierPath new] .CGPath; 'を意味しました。したがって、2つのケースの違いは、 'a'はobjcメッセージの結果を取得し、' b'はC関数の結果を取得することだけです。私はなぜARCがこれらのケースを別々に扱うべきかわかりません。 –

関連する問題