7

ブロックを使用して再帰を作成しようとしています。しばらくは動作しますが、最終的にクラッシュし、不正なアクセス例外が発生します。再帰ブロックを使用する場合のEXC_BAD_ACCESS

BOOL (^Block)(Square *square, NSMutableArray *processedSquares) = ^(Square *square, NSMutableArray *processedSquares) { 
    [processedSquares addObject:square]; 

    if (square.nuked) { 
     return YES; // Found a nuked square, immediately return 
    } 

    for (Square *adjacentSquare in square.adjacentSquares) { 
     if ([processedSquares containsObject:adjacentSquare]) { 
      continue; // Prevent infinite recursion 
     } 

     if (Block(adjacentSquare, processedSquares)) { 
      return YES; 
     } 
    } 

    return NO; 
}; 

__block NSMutableArray *processedSquares = [NSMutableArray array]; 
BOOL foundNukedSquare = Block(square, processedSquares); 

説明:これは私のコードで私はBOOL nukedを持ってSquareクラスを持っています。また、他の正方形を含むNSArray adjacentSquaresもあります。

正方形か、その「接続された」正方形のいずれかが裸であるかどうかをチェックしたいと思います。

アレイprocessedSquaresは、無限再帰を防ぐためにチェックした四角形を追跡することです。

これを実行すると、(期待どおり)このブロックの呼び出しが多発しています。しかし、ある時点では、不正なアクセス例外を伴う最後の行でクラッシュします。私も、コンソールでこれを取得

は、アドレス0x1の
でメモリにアクセスすることはできませんアドレス0x1の
でメモリにアクセスすることはできませんが、アドレス0x1の
でメモリにアクセスすることはできませんアドレス0x1の
でメモリにアクセスすることはできません警告:現在のスレッドのスタック上でcall-objcコードをキャンセルすると、これは安全ではありません。

私はブロックと再帰に慣れていません。何か案は?


編集1

要求されたとして、バックトレース:

#0 0x00000001 in ?? 
#1 0x000115fb in -[Square connectedToNukedSquare] at Square.m:105 
#2 0x00010059 in __-[Bot makeMove]_block_invoke_1 at Bot.m:94 
#3 0x91f3f024 in _dispatch_call_block_and_release 
#4 0x91f31a8c in _dispatch_queue_drain 
#5 0x91f314e8 in _dispatch_queue_invoke 
#6 0x91f312fe in _dispatch_worker_thread2 
#7 0x91f30d81 in _pthread_wqthread 
#8 0x91f30bc6 in start_wqthread 

答えて

14

:ここでは私のため正常に動作し完全な例だ、多分それはあなたの間違いを見つけるのを助けることができます)がブロック内で参照されると、その現在のがブロックにコピーされます。あなたのコードのBlockにはまだ値が与えられておらず、割り当てのブロックを構成しているので...あなたのブロックは、その再帰呼び出しBlockはそれへの参照がその値を取得するために使用され、値を持っている可能時間によって、再帰呼び出しはOKです -

__blockプレフィックスは参照、変数を渡します。

__blockがなくても、なぜ私の仕事が全く役に立たないのか分かりません。しかし、修飾子を使用すると、少なくとも10,000の深さまで再帰することができます。スタックのスペースは問題ではありません。

+0

ああ、私はそれを逃したとは思わない。真剣に。良いキャッチ。私の無回答を削除しました(しかし、まだその配列に '__block'は必要ありません)。 – bbum

+0

これは私のために働いた。ありがとうございました! – Rits

+0

私はこのブロックで「ブロック」を強く捕まえることで警告を受けていましたが、保持サイクル*につながる可能性があります。解決策がここに表示されます:http://stackoverflow.com/questions/15638751/how-to-fix-capturing-block-strongly-in-this-block-is-likely-to-lead-to-a-reta – ishahak

0

あなたは、配列を横断しながら、配列にsquaresを追加しているように見えます。私は、このラインの話だ。それをしなければならない

[processedSquares addObject:square];

のでしょうか?トラバース中にオブジェクトを追加しています。私はこれがまったく動作することに驚いています。

+0

OPは、処理されているアレイを列挙しているようには見えません。 – bbum

1

設定に何か間違っているのが好きです - あなたのSquareのオブジェクトはおそらく何とかうんざりしています。

__block BOOL (^Block)(Square *square, NSMutableArray *processedSquares); 
Block = ^(Square *square, NSMutableArray *processedSquares) { 

とき変数(Block:あなたがに宣言を変更、__blockBlockに必要

#include <stdio.h> 
#include <Foundation/Foundation.h> 

@interface Square : NSObject 
{ 
    BOOL nuked; 
    NSArray *adjacentSquares; 
} 

@property(nonatomic) BOOL nuked; 
@property(nonatomic, retain) NSArray *adjacentSquares; 
@end 

@implementation Square 

@synthesize nuked; 
@synthesize adjacentSquares; 

@end; 

BOOL (^Block)(Square *square, NSMutableArray *processedSquares) = ^(Square *square, NSMutableArray *processedSquares) { 
    [processedSquares addObject:square]; 

    if (square.nuked) { 
    return YES; // Found a nuked square, immediately return 
    } 

    for (Square *adjacentSquare in square.adjacentSquares) { 
    if ([processedSquares containsObject:adjacentSquare]) { 
     continue; // Prevent infinite recursion 
    } 

    if (Block(adjacentSquare, processedSquares)) { 
     return YES; 
    } 
    } 

    return NO; 
}; 

int main(int argc, char **argv) 
{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    Square *s1, *s2; 
    s1 = [[Square alloc] init]; 
    s2 = [[Square alloc] init]; 
    s1.adjacentSquares = [NSArray arrayWithObjects:s2, nil]; 
    s2.adjacentSquares = [NSArray arrayWithObjects:s1, nil]; 

    __block NSMutableArray *processedSquares = [NSMutableArray array]; 
    BOOL foundNukedSquare = Block(s1, processedSquares); 
    printf("%d\n", foundNukedSquare); 

    [s1 release]; 
    [s2 release]; 

    [pool release]; 

    return 0; 
} 
関連する問題