1

この議論に続いて、私は悪いアクセスの問題に遭遇しました。

ループにはいくつかのステップがあります:a、b、c、... x、y、z:

-(void)cycle:(float)delta{
[self stepA]
[self stepB]
// etc.
[self stepZ]
}

ある時点で、ステップxは次のことを行います。

// IRQ is an NSMutableArray
// Self is a reference to the engine running the cycles
[IRQ addObject:^{ NSLog(@"hello! %@", self); } ];

後で、ステップzは、すべての「遅延」呼び出しを処理することです。

            for (int i = 0; i < [IRQ count]; i++){
                void (^delayedCall)(void) = [IRQ objectAtIndex:i];
                delayedCall();
            }

            [IRQ removeAllObjects];

結果:EXEC_BAD_ACCESS

ここで、ステップxが次のようにオブジェクト参照のないプレーンな文字列のみを追加する場合、ステップZは正常に機能します。

[IRQ addObject:^{ NSLog(@"hello!"); } ];

最後の観察では、同じステップが両方ともキューにブロックを追加し、キューを繰り返してブロックを実行する場合、問題は発生しません。オブジェクトへの参照がステップとして「失われる」ように:メソッドは残っていますか?

私はこの分野についてあまり理解していないので、もっと助けが必要です!

編集:ジェームズ、その参照サイクルを避けるために次のことを試みました:

NSString *userName = @"James";
[IRQ addObject:^{ NSLog(@"hello %@", userName); } ];

そしてそれも起こります。あなたのソリューションはこれにどのように適用されますか?

前もって感謝します!

4

3 に答える 3

3

^{}構文を使用してブロックを作成すると、スタック上に作成されます。ブロックを長期間(ブロックを作成する関数の範囲を超えて)永続化するには、ブロックをヒープにコピーする必要があります。

void (^ myBlock)(void) = ^ {
    // your block code is here.
};
[IRQ addObject:[[myBlock copy] autorelease]];

ARCを使用している場合は、-autoreleaseメッセージをスキップしてください。

于 2012-06-30T23:15:57.097 に答える
3

問題は、ブロックオブジェクトがスタック上に作成されることです。ブロックが宣言されたスコープが破棄された後に使用されることが予想される場合、およびブロックがコピーされない場合は、ブロックをヒープにコピーする必要があります。

ここでは、ブロックを認識しないメソッドに「スタックのダウン」オブジェクトを渡します。交換

[IRQ addObject:^{ NSLog(@"hello! %@", self); } ];

[IRQ addObject:[^{ NSLog(@"hello! %@", self); } copy]];

そしてEXC_BAD_ACCESSこの時点で消えます。

ただし、ほとんどの場合、ブロックをコピーする必要はありません。いくつかの例:

  1. メソッドからブロックを返す場合(「スタックの上位」)、ARCはそれを自動的にコピーします。
  2. ブロックを保持しないメソッドを呼び出す場合、ブロックはスコープ内にとどまるため、ブロックをコピーする必要はありません。例:に渡されたブロック-[NSArray sortedArrayUsingComparator:]
  3. 後でブロックを使用するメソッドを呼び出す場合は、メソッドがブロックのコピーを担当する必要があります。そうしないと、すべての呼び出し元がブロックをコピーする必要があります。私が知っているAppleのライブラリのすべてのメソッド/関数は、そのパターンに従います。例:に渡された完了ブロック+[UIView animateWithDuration:options:animations:completion:]
于 2012-06-30T23:17:17.987 に答える
0

あなたが渡したオブジェクトのようです。あなたの例では:selfそしてuserName時期尚早に割り当てが解除されています。これは、私がブロックに期待する動作ではありません。以前の回答と同様に、保持が多すぎるために問題が発生すると予想していました。

テストとして、次のことを試してみてください。

NSString *userName = [@"James" retain];
[IRQ addObject:^{ NSLog(@"hello %@", userName); } ];

これはメモリリークになりますが、オブジェクトの割り当てが解除されているかどうかを示すのに役立ちます。

selfこれは、ブロックが保持され、ブロックを保持している「保持サイクル」によって引き起こされselfます。

これを試して:

__block typeof(self) blockSafeSelfReference = self;
[IRQ addObject:^{ NSLog(@"hello! %@", blockSafeSelfReference); } ];

ARCを使用する場合は、__unsafe_unretained代わりにを使用してください__block

于 2012-06-30T23:06:02.223 に答える