Me gustaría llamar recursivamente un bloque desde dentro de sí mismo. En un objeto obj-c, tenemos que usar "self", ¿hay algo como esto para referirse a una instancia de bloque desde su interior?¿Hay un puntero SELF para los bloques?
Respuesta
¡Historia divertida! Los bloques en realidad son objetos Objective-C. Dicho esto, no hay API expuesta para obtener el puntero self
de bloques.
Sin embargo, si declara bloques antes de usarlos, puede usarlos recursivamente. En un entorno no recolección de basura, que haría algo como esto:
__weak __block int (^block_self)(int);
int (^fibonacci)(int) = [^(int n) {
if (n < 2) { return 1; }
return block_self(n - 1) + block_self(n - 2);
} copy];
block_self = fibonacci;
Es necesaria aplicar el modificador __block
a block_self
, porque de lo contrario, la referencia block_self
dentro fibonacci
se referiría a ella antes de que está asignado (bloqueando su programa en la primera llamada recursiva). El __weak
es para garantizar que el bloque no capture una referencia fuerte a sí mismo, lo que causaría una pérdida de memoria.
Usted tiene que declarar la variable de bloque como __block
:
typedef void (^MyBlock)(id);
__block MyBlock block = ^(id param) {
NSLog(@"%@", param);
block(param);
};
@Joe Blow ['__block' específicamente es una palabra clave] (http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#// apple_ref/doc/uid/TP40007502-CH6-SW6). –
Este código también se fugará por la misma razón que el código de zneak. – Karl
El siguiente bloque de código recursivo compilar y ejecutar utilizando ARC, GC, o la gestión de memoria manual, sin que se caiga, fugas, o la emisión de advertencias (analizador o regular):
typedef void (^CountdownBlock)(int currentValue);
- (CountdownBlock) makeRecursiveBlock
{
CountdownBlock aBlock;
__block __unsafe_unretained CountdownBlock aBlock_recursive;
aBlock_recursive = aBlock = [^(int currentValue)
{
if(currentValue >= 0)
{
NSLog(@"Current value = %d", currentValue);
aBlock_recursive(currentValue-1);
}
} copy];
#if !__has_feature(objc_arc)
[aBlock autorelease];
#endif
return aBlock;
}
- (void) callRecursiveBlock
{
CountdownBlock aBlock = [self makeRecursiveBlock];
// You don't need to dispatch; I'm doing this to demonstrate
// calling from beyond the current autorelease pool.
dispatch_async(dispatch_get_main_queue(),^
{
aBlock(10);
});
}
consideraciones importantes:
- Usted debe copiar el bloque en el montón manualmente o de lo contrario intentará acceder a una pila inexistente cuando lo llame desde otro contexto (ARC generalmente hace esto por usted, pero no en todos los casos). Es mejor ir a lo seguro).
- Necesita DOS referencias: una para mantener la referencia fuerte al bloque y otra para mantener una referencia débil para el bloque recursivo para llamar (técnicamente, esto solo es necesario para ARC).
- Debe usar el calificador __block para que el bloque no capture el valor aún no asignado de la referencia de bloque.
- Si está realizando la administración manual de la memoria, deberá liberar automáticamente el bloque copiado.
Esto no funcionaría en ARC, pero ¿qué pasa con '' 'copy] liberación automática]' '' en lugar de solo copiar, por lo que no tiene que llamar a la versión dentro del bloque? Para ARC, tal vez haga '' 'aBlock = nil''' después de llamar' '' aBlock (10); '' '? –
En realidad, al volver a visitar esta solución, resulta que mantener la referencia dentro del bloque provocaría una fuga si no se llamaba al bloque. He actualizado la respuesta para que funcione correctamente, ya sea que la llame o no. – Karl
Tengo un problema que agrega una capa de complejidad a esto, pero no estoy del todo seguro de que mi problema se pueda resolver. Me gustaría poder volver a intentar llamadas API a través de AFNetworking. Creo que este pastebin simplifica e ilustra el problema. http://pastebin.com/xRPJuckZ El bloque recursivo no seguro que no se ha conservado se llama desde dentro de otro bloque dentro de sí mismo y llamarlo allí genera una excepción de acceso incorrecto. ¿Tendría alguna idea de cómo resolver esto? –
No hay self
para bloques (todavía). Usted puede construir uno como este (suponiendo ARC):
__block void (__weak ^blockSelf)(void);
void (^block)(void) = [^{
// Use blockSelf here
} copy];
blockSelf = block;
// Use block here
se necesita la __block
para que podamos establecer blockSelf
al bloque después de crear el bloque. El __weak
es necesario porque, de lo contrario, el bloque tendría una fuerte referencia a sí mismo, lo que provocaría un fuerte ciclo de referencia y, por lo tanto, una pérdida de memoria. El copy
es necesario para asegurarse de que el bloque se copie en el montón. Eso puede ser innecesario con versiones de compilador más nuevas, pero no hará ningún daño.
- 1. bloques, self, retener ciclos
- 2. ¿Hay alguna razón para no usar "esto" ("Self", "Me", ...)?
- 3. ¿Hay un puntero perezoso en C++?
- 4. ¿Cómo obtengo el valor int de object_getIvar (self, myIntVar) ya que devuelve un puntero
- 5. ¿Hay bloques y libdispatch disponibles en Linux?
- 6. python y usar 'self' en los métodos
- 7. C++ borrar un puntero a un puntero
- 8. ¿Hay un selector de CSS para seleccionar texto (bloques en línea) dentro de un cuadro rectangular?
- 9. self.delegate = self; ¿Qué hay de malo en hacer eso?
- 10. puntero a un puntero
- 11. Release, Dealloc y Self Reference
- 12. Software para marcar los bloques defectuosos en la tarjeta SD?
- 13. Rendimiento para múltiples bloques
- 14. HttpURLConnection.getInputStream() bloques
- 15. [self release], [self dealloc] o [super dealloc] en los métodos init?
- 16. ¿Cuál es la ventaja de tener this/self puntero obligatorio explícito?
- 17. Python TPCServer rfile.read bloques
- 18. ¿Cómo se elimina un puntero sin borrar los datos a los que apunta el puntero?
- 19. Self Sorting Listbox
- 20. Self hosted S3 alternativa
- 21. ¿Cómo se selecciona child-or-self (niños + self)
- 22. qué hay conversión implícita de puntero para hacer referencia a puntero constante
- 23. ¿Beneficios de los bloques de scoping?
- 24. Probar/atrapar bloques dentro de los constructores
- 25. ¿Inspeccionar los bloques GCD en cola?
- 26. ¿Hay alguna manera mejor que analizar/proc/self/maps para descubrir la protección de memoria?
- 27. var self = esto?
- 28. ámbito variable en los bloques de instrucciones
- 29. ¿La mejor explicación de los bloques Ruby?
- 30. ¿Cómo calcula el comando stat los bloques de un archivo?
Excelente respuesta. el modificador de bloque __ debería haberme tomado un tiempo para resolverlo por mi cuenta. ¡Gracias una tonelada! ¡Rep para ti! –
Si pasa a una función que terminará copiándola (como 'dispatch_async()'), también debe copiar el bloque en el alcance de la tarea. –
Este código tendrá fugas, incluso si tiene una condición de terminación. Agregue una variable de cuenta regresiva y ejecútela a través del inspector de fugas de Instruments para ver.Además, el compilador emitirá la siguiente advertencia si tiene activadas las advertencias correctas: "Capturar 'myBlock' en este bloque probablemente lleve a un ciclo de retención" – Karl