2010-04-17 7 views
19

Estoy tratando de entender los bloques. Obtengo cómo usarlos normalmente, cuando pasan directamente a un método. Ahora estoy interesado en tomar un bloque, almacenarlo (decir) en una variable de instancia y llamarlo más tarde.Copiando bloques (es decir, copiándolos a variables de instancia) en Objective-C

La guía de programación de bloques hace que suene como que puedo hacer esto, usando Block_copy/retain para copiar el bloque de distancia, pero cuando intento ejecutarlo, cuelgo mi programa.

- (void) setupStoredBlock 
{ 
    int salt = 42; 
    m_storedBlock = ^(int incoming){ return 2 + incoming + salt; }; 
    [m_storedBlock retain]; 
} 

que intente llamar más tarde:

- (void) runStoredBlock 
{ 
    int outputValue = m_storedBlock(5); 
    NSLog(@"When we ran our stored blockwe got back: %d", outputValue); 
    [m_storedBlock release]; 
} 

Cualquier persona tiene cualquier idea? (O, ¿hay algo que no estoy consiguiendo con bloques?)

¡Muchas gracias!

+0

pude reproducir esto en una aplicación de prueba: https://bitbucket.org/boredzo/block-retention-test/ –

Respuesta

30

Usted querrá hacer esto en su lugar:

- (void) setupStoredBlock 
{ 
    int salt = 42; 
    m_storedBlock = Block_copy(^(int incoming){ return 2 + incoming + salt; }); 
} 
+0

Este parece ser un error, ya sea en bloques o en la documentación. Blocks Programming Topics (http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/Blocks/Articles/bxUsing.html#//apple_ref/doc/uid/TP40007502-CH5-SW2) dice 'retener' Deberia trabajar. En mis pruebas, conservar un bloque se comportó normalmente (es decir, no devuelve una copia), pero cuando se asigna el bloque a una variable de instancia, al invocarlo desde un mensaje posterior se bloquea como se describe en la pregunta. Cambiar la retención a una copia (ya sea usando 'copy' o' Block_copy') corrige el bloqueo. –

+8

Ah. Sin errores. Aquí está el bbum en su blog: "Para un bloque que no ha sido copiado, -retain no tiene sentido. No hace nada. Se podría haber implementado para devolver una copia del Bloque, pero eso habría sido una bifurcación del contrato de retención más allá de lo aceptable. "Http://www.friday.com/bbum/2009/08/29/blocks-tips -tricks/Así que, sí, necesitas copiarlo-'retain' no funcionará aquí. –

+0

@Peter, sí, es una configuración interesante. Desearía que '-retain' tuviera la misma semántica con bloques a los que estamos acostumbrados con los objetos, pero hay ocasionales errores, como este. :( –

6

Copiar un bloque cuando se desea que permanezca alrededor. Autorelease o libérelo cuando haya terminado con él. Consérvelo si necesitas un largo camino para deletrear /* NOP */.

@interface Foo : FooSuper {} 
@property(copy) int (^storedBlock)(int); 
@end 

@implementation Foo 
@synthesize storedBlock = mStoredBlock; 

- (void)setupStoredBlock { 
    self.storedBlock = ^{/*...*/}; 
    // or: mStoredBlock = [^{/*...*/} copy]; 
    // but this simple implementation violates the atomicity contract 
} 

- (void)runStoredBlock { 
    int result = self.storedBlock(5); 
    NSLog(@"%s: result = %d", __func__, result); 
} 
@end 
+2

retener solo es no-operativo en bloques de pila Para bloques de bloques, retienen – user102008

4

Hubo una muy buena presentación sobre ese tema en la reciente WWDC (2010). Describió cómo se implementaron los bloques y por qué necesita usar Block_copy. Puede descargar una película de la presentación en: http://developer.apple.com/itunes/?destination=adc.apple.com.4092414566 La película se llama: "Opciones avanzadas de Objective-C y la recolección de basura"

+0

En realidad, el video recomienda utilizar el método de copia, no Block_copy. Citar alrededor de 23:50: "También hay funciones C para copiar y eliminar bloques (es decir, Block_copy). Si está escribiendo pure Código C, puede usar esas funciones C. En su lugar, debería preferir utilizar los métodos en lugar de las funciones, especialmente si está utilizando la recolección de elementos no utilizados. " – DougW

5

• Al igual que todas las variables locales, existe un bloque no estático en la pila y se le apareció desde la pila, como cualquier otra variable local que no ha sido declarada estática.

• Block_copy() copia el bloque de la pila en el montón, donde existen todas las instancias de malloc. Y como todos los métodos nuevos/de copia, Block_copy() devuelve un objeto alojado de montón con un conteo de retención de 1. Un bloque es un objeto objetivoC pero no se conforma como un objeto normal. Por lo tanto, no debería haber diferencia entre Block_Release() y el método de lanzamiento objetivo.

• Este ejemplo utiliza el método de copia de una instancia de bloque. Debido a que asignar el resultado de un Block_copy() a un id requiere un tipo de conversión que no quiero equivocarme. El método de copia permite que la variable de bloque se asigne directamente a una identificación.

- (void) setupStoredBlock 
{ 
    int zStackLocalVariable = 42; 
    iHeapAllocatedVariable = [^int(int aMore){ return zStackLocalVariable + aMore; } copy]; 
} 

• Declarar un objeto estático es requerir que se asigne físicamente con el código mismo. Un bloque que se declara estático no permite al compilador acceder a variables fuera de su propio ámbito. Debido a los requisitos de una declaración de bloque estático, supongo que el bloque en la pila es de alguna manera diferente del bloque que está en el montón.

• Un bloque es un objeto objetivo cuya clase cuyo nombre de clase y otra información asociada aún no he intentado recuperar, pero, como Protocolo, Objeto y otras clases ocultas de objetivoC, no se ajusta a NSObject. Sin embargo, al igual que todos los objetos de ObjectC, debe cumplir con retener/liberar. ARC amplía las equivalencias de retención/liberación en los objetos de Core Foundation también, y probablemente, si no ahora, luego eventualmente, en asignaciones malloc/free.

• Espero la verdadera motivación para una exploración exhaustiva de mikeash.com, ya que a Apple le gusta mantenernos a todos en un plano hiper-teórico de poca importancia física, aunque todo lo que es significativo es físico.

ARC and blocks also discussed here

+1

Nice answe r. Para el punto dos, ¿sería correcto decir que un bloque es un objeto Objective-C pero que no es una subclase 'NSObject'? O, ¿a qué te refieres con "no conformarse como un objeto normal"? Además, tengo problemas para entender el tamaño físico variable, y la frase "los bloques solo pueden acceder a sus propios parámetros ..." tampoco me resulta clara. ¿Hay alguna referencia que pueda ver, o puede decirlo de otra manera? –

+0

"sino también todas las variables de pila externas al bloque utilizadas en el bloque mismo" No, las variables externas se copian cuando se crea el bloque, no cuando se copia. – newacct

Cuestiones relacionadas