7

Estoy tratando de crear recursividad usando bloques. Funciona por un tiempo, pero finalmente se cuelga y me da una excepción de acceso incorrecto. Este es mi código:EXC_BAD_ACCESS al usar el bloque recursivo

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

Explicación: Tengo una clase que tiene un Square BOOL nuked. También tiene un NSArray adjacentSquares que contiene otros cuadrados.

Quiero comprobar si un cuadrado, o uno de sus cuadrados 'conectados', está numerado o no.

La matriz processedSquares es para realizar un seguimiento de los cuadrados que he comprobado para evitar la recursión infinita.

Cuando ejecuto esto, está haciendo muchas llamadas de este bloque (como se esperaba). Pero en algún momento, se bloquea en la última línea con una excepción de acceso incorrecto.

También consigo esto en la consola:

No se puede acceder a la memoria en 0x1 dirección
No se puede acceder a la memoria en la dirección 0x1
No se puede acceder a la memoria en la dirección 0x1
No se puede acceder a la memoria en la dirección 0x1
advertencia: la cancelación de la llamada - código objc en la pila del hilo actual lo hace inseguro.

No estoy tan familiarizado con los bloques y la recursividad. ¿Algunas ideas?


Editar 1

lo solicitado, la traza inversa:

#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 

Respuesta

14

Se necesita una __block en Block, cambiar la declaración a:

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

Cuando una variable (Block) se hace referencia dentro de un bloque luego se copia su valor actual en el bloque. En su código Block aún no se le ha dado un valor, ya que está construyendo el bloque en la tarea ...

El prefijo __block pasa por la variable de referencia - en el momento de su bloque que hace la llamada recursiva Block tiene un valor, la referencia a que se utiliza para obtener ese valor, y la llamada recursiva está bien.

No sé por qué funcionó en absoluto para usted sin el __block - error al instante para mí. Con el modificador, sin embargo, puedo recurrir a una profundidad de al menos 10.000, ¡así que el espacio de pila no es un problema!

+0

Oh, duh, no puedo creer que me haya perdido eso. Seriamente. Buena atrapada. Eliminé mi falta de respuesta (aún así no necesito '__block' en esa matriz). – bbum

+0

Esto funcionó para mí. ¡Gracias! – Rits

+0

Recibí una advertencia de * Capturar fuertemente 'bloque' en este bloque es probable que conduzca a un ciclo de retención *. Aquí aparece una solución: http://stackoverflow.com/questions/15638751/how-to-fix-capturing-block-strongly-in-this-block-is-likely-to-lead-to-a-reta – ishahak

0

Usted parece ser la adición de squares a la matriz al atravesar la matriz. Estoy hablando de esta línea:

[processedSquares addObject:square];

Poder que tienen que ver con esto? Está agregando un objeto al atravesarlo. Me sorprende que esto funcione en absoluto.

+0

OP no parece estar enumerando la matriz que se está procesando. – bbum

1

Te gusta hacer algo mal con la configuración: tus objetos Square probablemente estén en mal estado de alguna manera. Aquí está un ejemplo completo que funciona bien para mí, tal vez puede ayudarle a encontrar su error:

#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; 
} 
Cuestiones relacionadas