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