2016-11-17 9 views
4

の更新に失敗します問題は、これがすべてコンパイルされ実行されている間に、ブロックが戻ったときにブロックのアクションがすぐに忘れられることです。 [iWillNotDoWhatImSupposedTo]ランニングのプリントアウトは、次のとおりです。Objective Cの間接的なポインタは、私がこのように、ブロックに間接的なポインタを結合し、直接ポインタに後で割り当てのためのブロックを返す関数を持っている直接ポインタ

directPointer is pointing to: 0x0 
&directPointer is pointing to: 0x7fff5ce1d060 
--- callback execution starts here 
indirectPointer is pointing to: 0x7fff5ce1d050 
*indirectPointer is pointing to: 0x0 
After assignment: indirectPointer is pointing to: 0x7fff5ce1d050 
After assignment: *indirectPointer is pointing to: 0x61800001e1d0 
--- callback returns here, and the contents of the pointer is lost 
after running callback directPointer is pointing to: 0x0 
after running callback &directPointer is pointing to: 0x7fff5ce1d060 

私はこのコールバックを動作させることができる方法のための任意の洞察力?

+0

どのように起こっているのかよく分かりませんが、直接ポインタのあるアドレスがindirectPointerのアドレスと異なっていることに興味があります。 –

+0

実際のコードでは、設定するivarのアドレスを渡しますか?それ以外の場合は、ブロックで新しいインスタンスを直接返すようにしてください。 –

答えて

1

ブロックの外側から新しく作成されたオブジェクトを強く参照する必要があると思います。たとえば、ホルダークラスでこれを実現することができます。

@inferface Holder: NSObject 
@property (strong) id object; 
@end 
@implementation Holder 
@end 

- (CallbackType)getCallbackToAssignTo:(Holder *)inHolder { 
    return ^(int a){ 
     inHolder.object = [[SomeClass alloc] init]; 
     [inHolder.object setAnInt:a]; 
    }; 
} 

- (void)thisShouldWork { 
    Holder *theHolder = [Holder new]; 
    CallbackType cb = [self getCallbackToAssignTo:theHolder]; 

    cb(1); 
    SomeClass *directPointer = theHolder.object; 
} 
1

問題は実際には引数の自動解放です。実際メソッドシグネチャ:

- (CallbackType)getCallbackToAssignTo:(SomeClass * __autoreleasing *)indirectPointer; 

__autoreleasingを参照することにより(ID *)を渡され、リターン時に自動解放された引数を表すために使用されている:

- (CallbackType)getCallbackToAssignTo:(SomeClass **)indirectPointer; 

はに実際に等価です。

解決策は、生涯修飾子として__strongを指定することです。それはパラメータが、あなたは「強いへのポインタを」渡している「自動解放へのポインタ」であるという事実に関係しているという点で、Double pointer as Objective-C block parameter

4

Idali正しいです:より多くのSO参照が

- (CallbackType)getCallbackToAssignTo:(SomeClass * __strong *)indirectPointer; 

。しかし、を理解することは重要です。なぜなら、はこれと関連があります(ほとんどの場合、関連性がないためです)。それ自体は参照カウント自体とは関係ありません。

あなたは「強いへのポインタ」の引数として渡している(directPointerSomeClass * __strongであり、したがって&directPointerSomeClass * __strong *ある)「自動解放へのポインタ」であるパラメータに、。これはどのように作動しますか? ARCはこれを「pass-by-writeback」という手法で処理します。

"autoreleasing"型の一時変数を作成し、それに強力なポインタを割り当てて(値がnullでない場合)、この一時変数へのポインタでメソッドを呼び出します。そして、メソッドが返った後、変数の値をあなたの強い変数に戻します。およそこのような何か:-getCallbackToAssignTo:方法が唯一の独自の実行中に、同期の引数を使用する場合、パス・バイ・ライトバックメカニズムとして、SomeClass * __strong *パラメータとSomeClass * __autoreleasing *パラメータの間には差はないであろうことを

SomeClass * __autoreleasing temporaryPointer = directPointer; 
CallbackType cb = [self getCallbackToAssignTo:&temporaryPointer]; 
directPointer = temporaryPointer; 

注意メソッドの実行中に加えられた変更が、もともとポインタを渡そうとした強い変数に確実に反映されるようにします。

ここで問題となるのは、メソッドの実行よりも長いデータ構造(ブロック)にポインタへのポインタを格納して(ブロックが返される)、後でそのコードの一部ポインタが指しているポインタを変更しようとしました。しかしポインタが指しているのは、もはやメソッドの実行後に使用されなくなった一時変数です。したがって、一時変数の変更は元の変数に反映されません。

さらに悪いことに、基本的には未定義の動作です。コンパイラーは、一時変数がパスバイパス方式で使用されなくなったことを確認し、その変数のメモリーを他のものに再利用する可能性があります。あなたが持っているものは、コンパイラがあなたがまだ使用することを期待していない変数へのぶら下がりのポインタです。そして、この問題は、パラメータタイプを「自動解放へのポインタ」から「強力なポインタへ」に変更することによって実際に解決されるわけではありませんが、この直接的なケースを修正する可能性のある書き戻しパスを取り除いても、ブロックがあなたが指している変数の範囲外で使用できる場所から戻ったり格納したりすることができます。基本的には、通常のCポインタを格納するときやブロックを持つときには、そのブロックが指す変数の有効期間を保証する手段がないため、(ブロックがObjective-Cオブジェクトポインタを取得した場合とは異なり、その場合はそれを保持する)。

関連する問題