ser recursivo recursividad que objective-c recursion automatic-ref-counting objective-c-blocks retain-cycle

objective c - recursividad - bloque recursivo y retener ciclos en ARC



que es ser recursivo (3)

La respuesta es no.

Parece que no podemos hacer nada mejor que usar el calificador __block.

__block void(^strawberryFields)(); strawberryFields = ^{ strawberryFields(); }; strawberryFields();

Gracias al artículo de Bill Bumgarner sobre bloques.

EDITAR:

__block __weak void(^strawberryFields)();

parece ser la forma preferida bajo ARC.

EDIT2:

No. La respuesta sugerida es acerca de las llamadas asincrónicas . Deseo y necesito llamadas sincrónicas, como en una llamada recursiva estándar normal.

EDITAR:

mientras

__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;

compila sin advertencia o errores, falla en tiempo de ejecución con un NULL almacenado en inseguro_apply.

Sin embargo esto:

- (void) applyToView: (UIView *) view { UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) { return [UIColor colorWithHue: ((CGFloat) index / 255.0f) saturation: 0.5f brightness: 0.5f alpha: 1.0f] ; } ; void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) { view.backgroundColor = colorForIndex(index) ; } ; void (^__block recurse_apply)(UIView *, NSInteger) ; void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) { applyColors(view, level) ; [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) { recurse_apply(subview, 1+level) ; }] ; } ; recurse_apply = apply ; apply(view, 0) ; }

compila sin advertencias, pero lo más importante, realmente se ejecuta.

¡Pero esto es tan feo !

considere (colorear la jerarquía de vista, para exponer el propósito ...) :

- (void) applyToView: (UIView *) view { UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) { return [UIColor colorWithHue: ((CGFloat) (index * 10.0f) / 255.0f) saturation: 0.5f brightness: 0.5f alpha: 1.0f] ; } ; void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) { view.backgroundColor = colorForIndex(index) ; } ; void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) { applyColors(view, level) ; [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) { apply(subview, 1+level) ; }] ; } ; apply(view, 0) ; }

Recibo esta advertencia:

/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:551:42: la Block pointer variable ''apply'' is uninitialized when captured by block

Si aplico la solución sugerida: Maybe you meant to use __block ''apply''

void (^__block apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {

Luego obtengo: /Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:554:13: Capturing ''apply'' strongly in this block is likely to lead to a retain cycle

Intenté varias formas de alterar el código y deshacerme de esas advertencias

__weak typeof (apply) wapply = apply ; if (wapply) { __strong typeof (wapply) sappy = wapply ; wapply(subview, 1+level) ; }

Pero las cosas empeoran y se convierten en errores.

Terminé con esto:

__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ; void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) { applyColors(view, level) ; [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) { unsafe_apply(subview, 1+level) ; }] ; } ; unsafe_apply = apply ; apply(view, 0) ;

¿Alguien tiene una mejor solución, donde podría hacer todo desde dentro del bloque y no espantosamente hacer el parche como tenía que hacer aquí?

Tenga en cuenta que esas preguntas SO son sobre la captura de self y esas preguntas tan no tienen ninguna respuesta satisfactoria.


__block capturar una variable __block , porque los bloques capturan variables no __block por valor cuando se crean, y la asignación ocurre después de que se ha creado el bloque.

En ARC, __block variables del tipo puntero de objeto (generalmente todas las variables son implícitamente __strong ) son retenidas por el bloque. Entonces, si el bloque captura una variable __block que apunta a sí misma, crearía un ciclo de retención. La solución es hacer que capture una referencia débil. En las versiones del sistema operativo que admiten __weak , __weak debe usarse en lugar de __unsafe_unretained .

Sin embargo, si la única referencia al bloque fuera una variable __weak , no habría referencias fuertes al bloque, lo que significa que puede desasignarse. Para usar el bloque, debe tener una referencia fuerte para mantenerlo.

Por lo tanto, necesitas dos variables, una débil y una fuerte. La forma correcta de hacerlo en ARC es:

__block __weak void (^weak_apply)(UIView *, NSInteger) ; void (^apply)(UIView *, NSInteger) ; weak_apply = apply = ^(UIView * view, NSInteger level) { applyColors(view, level) ; [view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) { weak_apply(subview, 1+level) ; }] ; } ; apply(view, 0) ;


Para evitar las advertencias de ARC y desarrollar la respuesta de @newacct, encontré que funciona el bloqueo débil dentro del bloque retenido:

//a block definition typedef void (^CompletionType)(NSDictionary * __nullable response, NSError * __nullable error); //a block calling itself without the ARC retain warning __block CompletionType completionBlock = nil; __block __weak CompletionType weakCompletionBlock = nil; completionBlock = ^(NSDictionary *response, NSError *error) { weakCompletionBlock = completionBlock; weakCompletionBlock(); }); };