2012-08-06 26 views
5

In this question, me preguntaron sobre el siguiente código y retienen ciclos:referencias débiles en bloques y ciclos retener

__weak Cell *weakSelf = self; 
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ 
     UIImage *image = /* render some image */ 
     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      [weakSelf setImageViewImage:image]; 
     }]; 
    }]; 
    [self.renderQueue addOperation:op]; 

Todas las respuestas afirman que el uso de una referencia débil aquí no era necesario, ya que este código no se traduce en una retener el ciclo Sin embargo, mientras que la experimentación con algo más de código, a continuación se da lugar a un ciclo de retener (si no utilizo una referencia débil, el controlador de vista actual no se cancela la asignación)

//__weak ViewController *weakSelf = self; 
    MBItem *close = [[MBItem alloc] initWithBlock:^{ 
     [self dismissModalWithDefaultAnimation:NO]; 
    }]; 
    NSMutableArray *items = [[NSMutableArray alloc] initWithObjects:close, nil]; 
    [self.childObject setItems:items]; 

¿Por qué el segundo resultado en un ciclo de retención pero no el primero?

+2

La palabra clave es "Conservar CICLO". Al igual que en, te retengo y me retienes, entonces, ¿quién deja ir primero? –

Respuesta

12

Su antiguo código crea este ciclo retener si no se utiliza __weak:

  • (NSBlockOperation *)op conserva el bloque exterior
  • El bloque exterior conserva self (si no se está usando __weak)
  • self retiene (NSOperationQueue *)renderQueue
  • (NSOperationQueue *)renderQueue retiene (NSBlockOperation *)op

Ninguno de los objetos en ese ciclo puede ser desasignado a menos que uno de esos enlaces esté roto. Pero el código que nos mostró hace rompe el ciclo de retención. Cuando op termina de ejecutarse, renderQueue lo libera, rompiendo el ciclo de retención.

Sospecho que su nuevo código crea este ciclo retener:

  • (MBItem *)close conserva el bloque
  • El bloque retiene self
  • self conserva childObject
  • childObject conserva (NSMutableArray *)items
  • (NSMutableArray *)items conserva (MBItem *)close

Si no ocurre nada que rompa uno de esos enlaces, ninguno de los objetos en el ciclo puede desasignarse. No nos ha mostrado ningún código que rompa el ciclo de retención. Si no hay ningún evento que lo rompa explícitamente (por ejemplo, borrando childObject.items), entonces necesita usar __weak para interrumpir el ciclo de retención.

8

No puedo decirle el motivo del ciclo de retención en su segundo ejemplo, porque no sé MBItem, pero hay dos patrones de uso diferentes con bloques.

Si espera que su bloque debe ejecutarse en cualquier caso, a continuación, puedes utilizar self en el bloque:

[startSomeOperationWithCompletionBlock:^{ 
    [self doSomeThing]; 
}]; 

El bloque conserva una referencia a self, de manera que self no se desasigna antes de que el bloque es ejecutado. Pero después de que el bloque se haya ejecutado, esta referencia (y el ciclo de retención) se ha ido.

Si posiblemente desea que self se desasigna antes el bloque ha ejecutado, o si es posible que el bloque no será llamado en absoluto, entonces usted tiene que utilizar una referencia débil y comprobar el valor en el interior el bloque:

__weak MyClass *weakSelf = self; 
[startSomeOperationWithCompletionBlock:^{ 
    MyClass *strongSelf = weakSelf; 
    if (strongSelf) { 
     [strongSelf doSomeThing]; 
    } 
}]; 

el bloque no retiene self en este caso, de manera que self puede cancelar la asignación. En ese caso, weakSelf se establece automáticamente en nil. Por lo tanto, si el bloque se ejecuta finalmente, primero debe verificar si weakSelf sigue siendo válido. (O simplemente puede usar, porque el envío de mensajes a nil es un no-op.)

Asignación de una fuerte referencia strongSelf dentro del bloque impide self de ser desasignado mientras que el bloque está ejecutando.

+0

¿Qué ocurre si se ejecuta el bloque, pero todavía se mantiene en alguna matriz, para que pueda volver a utilizarse? Supongo que uno mismo no sería desasignado aquí, ¿hasta que se borre la matriz? – Snowman

+0

Sí, creo que eso es lo que @robmayoff ha descrito en su respuesta. –

+0

Crear una referencia fuerte a un puntero débil (o en mi caso __unsafe_unretained) dentro del bloque resolvió un problema similar que estaba teniendo donde la clase fue desasignada a mediados de la ejecución del bloque. ¡Gracias! – SRandazzo

Cuestiones relacionadas