Los bloques en línea iOS están bien, pero los bloques declarados como variables causan problemas de memory

Tengo un set de código que se parece a esto:

if(self.property == A) { [self.infoManager getThingA:^(NSString *thing, NSError *error) { self.textView.text = thing; }]; } else if(self.property == B) { [self.infoManager getThingB:^(NSString *thing, NSError *error) { self.textView.text = thing; }]; } 

Básicamente, en ambas instancias, solo obtienen una cadena para publicar en un TextView. La cadena es diferente según el método al que se llama.

Al ser alguien que generalmente está en contra de la duplicación de código, abstraí esto en una variable de bloque:

 void (^stringBlock)(NSString *thing, NSError *error) = ^void(NSString *thing, NSError *error) { self.textView.text = thing; } if(self.property == A) { [self.infoManager getThingA:stringBlock]; } else if(self.property == B) { [self.infoManager getThingB:stringBlock]; } 

Y todo estuvo bien por un time. Pero ahora estoy recibiendo errores en las testings de mi unidad donde parece que stringBlock está siendo desasignado demasiado pronto. Creo que esto porque obtengo EXC_BAD_ACCESS después de ejecutar el bloque, y el depurador dice que stringBlock es NULL.

No estoy copyndo explícitamente el bloque en mi método, ni en la testing de unidad.

El bloque que ha declarado anteriormente se denomina un bloque independiente (otro tipo se denomina bloques en línea que son como classs anónimas en línea en java). Al usar bloques independientes, debemos adherirnos a unas pocas reglas.

1. No puedes referirte a ti mismo en objects de bloque independientes. si es necesario, debe pasar el object propio al bloque como parámetro.

2. No puede acceder a las properties de un object dentro de un bloque Independiente utilizando la notación de puntos. Si necesita hacerlo, use los methods setter y getter.

Por lo tanto, en su caso, debemos pasar el autoobject al bloque como se muestra a continuación.

 void (^stringBlock)(NSString *thing, NSError *error, id self) = ^void(NSString *thing, NSError *error, id self) { self.textView.text = thing; } 

Intenta copyr el bloque. Las variables de bloques se crean en la stack y son válidas en el time de vida del scope, si copys, se mueven al montón.
Consulte este artículo por Mike Ash
También aquí en cocoa con amor y aquí