¿Qué es una regla simple para evitar el locking del bloque objective retener fugas en la memory del ciclo?

Lo he tenido con pérdidas de memory derivadas de los ciclos de retención de bloques. Me gustaría una simple regla que pueda aplicar a mi código para asegurarme de evitarlos. Por otro lado, no quiero actualizar la mitad de mi base de código base a __weak sin que sea necesario.

Esto es lo que tengo hasta ahora:

No puede haber pérdidas de memory cuando usa lo siguiente:

 dispatch_async(queue, ^{...}); // GCD call. [Foo bar:^{...}]; // Class "+" methods with completion block. 

Sin embargo, estos casos causarán fugas en la memory del ciclo de retención del bloque con security:

 self.myPropertyBlock = ^{ self; }; _myInstanceVariableBlock = ^{ self; }; self.myPropertyBlock = ^{ _selfInstanceVariable; }; obj.myPropertyBlock = ^{ obj; }; 

Y estos casos pueden o no causar fugas en la memory del ciclo de retención de bloque (dependiendo de si el object de llamada de bloque conserva el bloque):

 [self bar:^{ self; }]; [self.myPropertyObj bar:^{ self; }]; [self.myPropertyObj bar:^{ _selfInstanceVariable; }]; [obj bar:^{ obj; }]; [obj.myPropertyObj bar:^{ obj; }]; 

Para estar absolutamente seguro de que no puede haber pérdidas de memory, los casos problemáticos requieren cambiar los pointers obj u obj utilizados dentro de los bloques para __weak puntos __weak como este (o alguna otra estrategia para evitar fugas):

 __weak SelfClass *weakSelf = self; self.myPropertyBlock = ^{ weakSelf; }; _myInstanceVariableBlock = ^{ weakSelf; }; self.myPropertyBlock = ^{ weakSelf.instanceVariableConvertedToProperty; }; [self bar:^{ weakSelf; }]; [self.myPropertyObj bar:^{ weakSelf; }]; [self.myPropertyObj bar:^{ weakSelf.instanceVariableConvertedToProperty; }]; __weak ObjClass *weakObj = obj [obj bar:^{ weakObj; }]; [obj.myPropertyObj bar:^{ weakObj; }]; obj.myPropertyBlock = ^{ weakObj; }; 

Por favor, avíseme acerca de los casos incorrectos mencionados anteriormente.

¿Hay reglas más simples y mejores?

Sería increíble si pudieras agregar una pequeña explicación explicando por qué una regla funciona o no.

Regla basada en la respuesta: Considere todos los objects mencionados en el bloque y pregunte: ¿retienen este bloque alguno de estos objects?

Un ciclo de retención es cuando A -> B -> A (donde -> significa retiene). Es malo porque no podemos desasignar cosas retenidas, por lo que la única forma de desasignar A es desasignar B, pero eso depende de desasignar A.

Un ciclo de retención de bloque no es diferente, excepto que los bloques son más agresivos en cuanto a retención: retienen cualquier object referencedo dentro de ellos, por lo que si A -> Bloque y Bloque menciona A, entonces A -> Bloque -> A.

Todo esto conduce a una regla simple cuando se codifican bloques. Considere todos los objects mencionados en el bloque y pregunte: ¿retienen este bloque alguno de estos objects? La mayoría de las veces no lo hacen. Pero preste especial atención al object al que está pasando el bloque, en otras palabras:

 [beSuspiciousOfMe heresABlock:^{ NSLog(@"does %@ retain this block?", beSuspiciousOfMe]; }]; 

Si controla beSuspiciousOfMe (que puede ser, y muchas veces es uno mismo), esto es fácil de verificar. Si ese código es opaco por alguna razón, y no está seguro, puede usar el truco de copy débil.