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

说明:我有一个Square有 BOOL 的课程nuked。它还有一个adjacentSquares包含其他 Squares 的 NSArray。

我想检查一个正方形或它的“连接”正方形之一是否被核弹了。

该数组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,它的引用用于获取该值,并且递归调用正常。

我不知道为什么如果没有__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 回答