【问题标题】:EXC_BAD_ACCESS when using recursive block使用递归块时的 EXC_BAD_ACCESS
【发布时间】:2011-01-30 18:03:12
【问题描述】:

我正在尝试使用块创建递归。它工作了一段时间,但最终它崩溃并给了我一个糟糕的访问异常。这是我的代码:

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 包含其他 Squares。

我想检查一个方格,或者它的“连接”方格之一,是否有核弹。

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

【问题讨论】:

    标签: iphone objective-c cocoa-touch recursion objective-c-blocks


    【解决方案1】:

    您需要在Block 上添加__block,将声明更改为:

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

    当一个变量(Block)在一个块中被引用时,它的当前被复制到块中。在您的代码中 Block 尚未被赋予一个值,因为您正在构建分配中的块......

    __block 前缀通过 reference 传递变量 - 当您的块进行递归调用时,Block 有一个值,对它的引用用于获取该值,并且递归调用就OK了。

    如果没有__block,我不知道为什么它对你完全有效——对我来说直接失败了。但是,使用修饰符我可以递归到至少 10,000 的深度 - 所以堆栈空间不是问题!

    【讨论】:

    • 哦,呃,我不敢相信我错过了。严重地。接得好。删除了我的未回答(不过,该数组上仍然不需要__block)。
    • 我收到了警告,提示 在此块中强烈捕获“块”可能会导致保留周期。此处出现解决方案:stackoverflow.com/questions/15638751/…
    【解决方案2】:

    您喜欢在设置上做错事——您的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;
    }
    

    【讨论】:

      【解决方案3】:

      您似乎在遍历数组时将squares 添加到数组中。我说的是这一行:

      [processedSquares addObject:square];

      这可能与它有关吗?您在遍历时添加了一个对象。我很惊讶这完全有效。

      【讨论】:

      • OP 似乎没有枚举正在处理的数组。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-06
      • 2020-09-05
      • 2011-10-31
      相关资源
      最近更新 更多