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 в стеке текущего потока делает это небезопасным.

Я не знаком с блоками и рекурсией. Есть идеи?


Edit 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

Вам нужен __block на Block, изменить декларацию:

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

Когда переменная (Block) ссылается в пределах блока, тогда его текущий значение копируется в блок. В вашем коде Block еще не было задано значение, так как вы строите блок в задании ...

__block префикса передает переменный по ссылке - к тому времени, блок делает его рекурсивный вызов Block имеет значение, ссылка на него используются для получения этого значения, и рекурсивный вызов OK.

Я не знаю, почему все это сработало для вас без __block - я сразу же отказался. Тем не менее, с помощью модификатора я могу реорганизовать, по крайней мере, на глубину 10 000, поэтому пространство в стеке не проблема!

+0

О, я не могу поверить, что я пропустил это. Шутки в сторону. Хороший улов. Удалил мой не-ответ (все равно не нужен '__block' в этом массиве). – bbum

+0

Это сработало для меня. Спасибо! – Rits

+0

Я получал предупреждение для * Захват «блока» сильно в этом блоке, вероятно, приведет к циклу сохранения *. Решение появляется здесь: http://stackoverflow.com/questions/15638751/how-to-fix-capturing-block-strongly-in-this-block-is-likely-to-lead-to-a-reta – ishahak

0

Вы, кажется, добавляя squares в массив при обходе массива. Я говорю об этой линии:

[processedSquares addObject:square];

Мощь, что нужно сделать с этим? Вы добавляете объект во время прохождения. Я удивлен, что это работает вообще.

+0

ОП не представляется перечислением массива, который обрабатывается. – bbum

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; 
} 
Смежные вопросы