7

ブロックを使用して再帰を作成しようとしています。しばらくは動作しますが、最終的にはクラッシュし、アクセス不良の例外が発生します。これは私のコードです:

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);

説明:SquareBOOLを持つクラスがありnukedます。また、adjacentSquares他のSquareを含むNSArrayもあります。

正方形、またはその「接続された」正方形の1つが核兵器であるかどうかを確認したいと思います。

配列processedSquaresは、無限再帰を防ぐためにチェックした正方形を追跡するためのものです。

これを実行すると、(予想どおり)このブロックの呼び出しが多数実行されます。しかし、ある時点で、アクセス不良の例外が発生して最後の行でクラッシュします。

私もこれをコンソールで取得します:

アドレス0x1のメモリに
アクセスできませんアドレス0x1のメモリにアクセスできませんアドレス0x1のメモリに
アクセスできませんアドレス0x1のメモリにアクセス
できません
警告:呼び出しをキャンセルします-現在のスレッドのスタックの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
4

3 に答える 3

14

__blockonが必要ですBlock。宣言を次のように変更します。

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

変数(Block)がブロック内で参照されると、その現在のがブロックにコピーされます。割り当てでブロックを作成しているため、コードBlockにはまだ値が指定されていません...

__blockプレフィックスは参照によって変数を渡します-ブロックがその再帰呼び出しBlockに値を持たせるまでに、その参照はその値を取得するために使用され、再帰呼び出しはOKです。

なぜそれがあなたのためにまったく機能したのか分かりません__block-私にとってはすぐに失敗しました。ただし、モディファイアを使用すると、少なくとも10,000の深さまで再帰できます。したがって、スタックスペースは問題になりません。

于 2011-01-30T20:40:53.497 に答える
1

あなたはセットアップで何か間違ったことをするのが好きです-あなたのSquareオブジェクトはおそらくどういうわけか台無しにされています。これが私にとってうまく機能する完全な例です、多分それはあなたがあなたの間違いを見つけるのを助けることができます:

#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;
}
于 2011-01-30T20:16:36.410 に答える
0

squares配列をトラバースしているときに、配列に追加しているようです。私はこの行について話している:

[processedSquares addObject:square];

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

于 2011-01-30T18:21:55.690 に答える