2010-07-15 16 views
36

Estaba pensando, ya que puedes tratar bloques como objetos si creo dos de ellos y luego los agrego a un NSArray ¿hay alguna forma de ejecutarlos desde el arreglo?Ejecutando bloques desde NSArray?

int (^Block_001)(void) = ^{ return 101; }; 
int (^Block_002)(void) = ^{ return 202; }; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 

EDIT: Actualización para mayor claridad por una excelente respuesta de @ davedelong

int (^Block_001)(void) = [^{ return 101; } copy]; 
int (^Block_002)(void) = [^{ return 202; } copy]; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 

[Block_001 release]; 
[Block_002 release]; 
+2

Un buen conjunto de respuestas ... Vi el título y esperaba algunos puntos de repetición fáciles. La gente lo cubrió completamente. :) – bbum

+0

Solo un punto rápido, si no copias/sueltas, el bloque estará en la pila ... Entonces, si la pila se destruye, la aplicación se bloqueará ¿no? – fzaziz

Respuesta

29

Claro, sólo lo debe invocar con () como cualquier otro bloque, pero hay que encasillarse el valor que recupera de NSArray. He aquí un ejemplo (con un typedef añadido, porque de lo contrario me duele la cabeza):

typedef int (^IntBlock)(void); 
IntBlock Block_001 = ^{ return 101; }; 
IntBlock Block_002 = ^{ return 202; }; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 
int x = ((IntBlock)[array objectAtIndex:0])(); // now x == 101 
+0

bien, entonces no estoy familiarizado con los indicadores de función ¿estoy haciendo esto bien? El typedef define "IntBlock" que es un puntero a un bloque que devuelve un int y no toma argumentos. Creo que lo entiendo, y mirando la alternativa (que estoy bastante seguro de que me equivocaría) agradezco su decisión de ir con el typedef :) Muy apreciado. – fuzzygoat

+0

Sí, lo tienes. –

+1

No es necesario que lo lances. Funciona muy bien para hacer 'int (^ block)() = [array objectAtIndex: 0]'. Un puntero es un puntero es un puntero, después de todo, al menos en los lenguajes de bajo nivel como 'C' y sus derivadas. – aroth

6

Por supuesto que puedes.

int (^x)(void) = [array objectAtIndex:0]; 
printf("%d\n", x()); // prints 101. 
+0

Lo consideré muy interesante. ¿Puedes aclarar por mí, estoy en lo cierto al referirme a "int (^ x) (void)" como un puntero a un bloque? Solo estoy tratando de asegurarme de que estoy obteniendo la terminología correcta. – fuzzygoat

60

@KennyTM y @ David son correctos, pero su código es potencialmente mal. He aquí por qué:

Al crear un NSArray con objetos, se retain los objetos puestos en él. En el caso de bloques, está utilizando la función Block_retain. Esto significa que la matriz ha retenido los bloques que creó, pero que viven en la pila (los bloques son uno de los ejemplos muy raros de objetos Objective-C que se pueden crear en la pila sin profundizar en trucos absurdos). Eso significa que tan pronto como este método finalice, su matriz ahora apunta a la basura, porque los bloques a los que apuntaba ya no existen. Para hacer esto correctamente, usted debe hacer:

int (^Block_001)(void) = [^{ return 101; } copy]; 
int (^Block_002)(void) = [^{ return 202; } copy]; 
NSArray *array = [NSArray arrayWithObjects:Block_001, Block_002, nil]; 

[Block_001 release]; 
[Block_002 release]; 

Al invocar copy en el bloque, se está moviendo de manera explícita el bloque fuera de la pila y en el montón, donde puede permanecer con seguridad después de las salidas de métodos/funciones . Luego, después de agregar los bloques a la matriz, debe equilibrar su copy (debido a la regla NARC) con una llamada subsiguiente al release. ¿Tener sentido?

+0

Hola Dave, sí, entiendo, no estaba al tanto de los bloques que se están creando en la pila (hoy solo empecé a buscar bloques). Muy apreciado. – fuzzygoat

+0

Excelente punto sobre la necesidad de copiar –

+0

Hola Dave, encontré esta pregunta y la respuesta aceptada de David Gelhar, así que la implementé y funcionó bastante bien, ** no ** se bloqueó. Leyendo más, su respuesta tiene sentido pero no explica por qué el código de David no está fallando (¿de inmediato?). ¿Tienes alguna pista? – Tieme