7

Tôi đang cố gắng tạo đệ quy bằng cách sử dụng các khối. Nó hoạt động trong một thời gian, nhưng cuối cùng nó bị treo và cho tôi một ngoại lệ truy cập xấu. Đây là mã của tôi:EXC_BAD_ACCESS khi sử dụng khối đệ quy

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

Giải thích: Tôi có một lớp Square mà có một BOOL nuked. Nó cũng có một NSArray adjacentSquares chứa các ô vuông khác.

Tôi muốn kiểm tra xem một hình vuông hoặc một trong các hình vuông 'được kết nối' của nó có bị nhòe hay không.

Mảng processedSquares là để theo dõi các ô vuông tôi đã kiểm tra để ngăn chặn đệ quy vô hạn.

Khi tôi chạy điều này, nó thực hiện rất nhiều cuộc gọi của khối này (như mong đợi). Nhưng tại một số điểm, nó bị treo ở dòng cuối cùng với một ngoại lệ truy cập xấu.

Tôi cũng có được điều này trong bảng điều khiển

Không thể truy cập bộ nhớ tại 0x1 địa chỉ
Không thể truy cập bộ nhớ tại địa chỉ 0x1
Không thể truy cập bộ nhớ tại địa chỉ 0x1
Không thể truy cập bộ nhớ tại địa chỉ 0x1
cảnh báo: Hủy bỏ cuộc gọi - mã objc trên ngăn xếp của luồng hiện tại làm cho điều này không an toàn.

Tôi không quen thuộc với các khối và đệ quy. Bất kỳ ý tưởng?


Sửa 1

Theo yêu cầu, các vết lùi:

#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 

Trả lời

14

Bạn cần một __block trên Block, thay đổi việc kê khai để:

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

Khi một biến (Block) được tham chiếu trong một khối thì giá trị hiện tại của nó được sao chép vào khối. Trong mã số Block của bạn chưa được cung cấp một giá trị, vì bạn đang xây dựng khối trong nhiệm vụ ...

Các __block tiền tố vượt qua biến bằng cách tham khảo - vào thời điểm khối của bạn làm cho cuộc gọi đệ quy của nó Block có một giá trị, tài liệu tham khảo để nó được sử dụng để có được giá trị đó, và cuộc gọi đệ quy là OK.

Tôi không biết tại sao nó hoạt động hoàn toàn cho bạn mà không có __block - thất bại ngay lập tức đối với tôi. Tuy nhiên, với công cụ sửa đổi, tôi có thể sử dụng tối thiểu 10.000 độ sâu - vì vậy không gian ngăn xếp không phải là vấn đề!

+0

Ồ, duh, tôi không thể tin rằng mình đã bỏ lỡ điều đó. Nghiêm túc. Nắm bắt tốt. Đã xóa không trả lời của tôi (vẫn không cần '__block' trên mảng đó, mặc dù). – bbum

+0

Điều này làm việc cho tôi. Cảm ơn bạn! – Rits

+0

Tôi đã nhận được một cảnh báo cho * Chụp 'chặn' mạnh mẽ trong khối này có khả năng dẫn đến một chu kỳ giữ lại *. Một giải pháp xuất hiện ở đây: http://stackoverflow.com/questions/15638751/how-to-fix-capturing-block-strongly-in-this-block-is-likely-to-lead-to-a-reta – ishahak

0

Bạn dường như được thêm squares đến mảng trong khi vượt qua mảng. Tôi đang nói về dòng này:

[processedSquares addObject:square];

Might rằng phải làm gì với nó? Bạn đang thêm một đối tượng trong khi duyệt qua. Tôi ngạc nhiên rằng điều này làm việc ở tất cả.

+0

OP không xuất hiện để liệt kê mảng đang được xử lý. – bbum

1

Bạn đang thích làm điều gì đó sai với cài đặt - các đối tượng Square của bạn có thể bị rối loạn bằng cách nào đó. Dưới đây là một ví dụ hoàn chỉnh mà hoạt động tốt đối với tôi, có lẽ nó có thể giúp bạn tìm thấy sai lầm của mình:

#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; 
} 
Các vấn đề liên quan