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

解释:我有一个Square类具有BOOL nuked。它也有一个包含其他方块的NSArray adjacentSquares

我想检查一个正方形或它的一个“连接”正方形是否被烧毁。

数组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 

回答

14

你需要一个__blockBlock,改变声明:

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

当一个变量(Block )在一个块内被引用,那么它的当前被复制到该块中。在你的代码Block还没有被赋予一个值,因为你正在赋值中构造块...通过你的格挡使得其递归调用Block有一个价值,它的参考是用于获取价值的时间,递归调用OK -

__block前缀经过参考变量。

我不知道为什么它在没有__block的情况下为你工作 - 对我而言,这是不可能的。有了修饰符,我可以递归到至少10000的深度 - 所以栈空间不是问题!

+0

哦,呃,我不能相信我错过了那个。认真。接得好。删除了我的非答案(尽管如此,仍然不需要`__block`)。 – bbum 2011-01-31 07:22:05

0

你似乎增加squares到阵列,同时在遍历数组。我说这行:

[processedSquares addObject:square];

魔法门有什么关系呢?你在遍历时添加一个对象。我很惊讶,这可以工作。

+0

OP似乎没有枚举正在处理的数组。 – bbum 2011-01-30 19:33:07

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