Recuerde también que los ciclos de retención pueden ocurrir si su bloqueo se refiere a otro objeto que luego retieneself
.
No estoy seguro de que la recolección de basura pueda ayudar en estos ciclos de retención. Si el objeto que retiene el bloque (que llamaré el objeto del servidor) sobrevive self
(el objeto del cliente), la referencia aself
interior del bloque no se considerará cíclica hasta que se libere el objeto de retención. Si el objeto del servidor supera a sus clientes, es posible que tenga una pérdida de memoria significativa.
Como no hay soluciones limpias, recomendaría las siguientes soluciones. Siéntase libre de elegir uno o más de ellos para solucionar su problema.
- Use bloques solo para completar , y no para eventos abiertos. Por ejemplo, use bloques para métodos como
doSomethingAndWhenDoneExecuteThisBlock:
, y no métodos como setNotificationHandlerBlock:
. Los bloques utilizados para la finalización tienen un final definitivo de vida útil, y los objetos del servidor deben liberarlos después de evaluarlos. Esto evita que el ciclo de retención viva demasiado tiempo, incluso si ocurre.
- Haz ese baile de referencia débil que describiste.
- Proporcione un método para limpiar su objeto antes de liberarlo, que "desconecta" el objeto de los objetos del servidor que pueden contener referencias a él; y llame a este método antes de llamar a release en el objeto. Si bien este método está perfectamente bien si su objeto solo tiene un cliente (o es un singleton dentro de algún contexto), pero se descompondrá si tiene varios clientes. Básicamente estás derrotando el mecanismo de conteo de retención aquí; Esto es similar a llamar en
dealloc
lugar de release
.
Si está escribiendo un objeto de servidor, tome argumentos de bloque solo para completar. No acepte argumentos de bloque para devoluciones de llamada, como setEventHandlerBlock:
. En cambio, recurra al patrón de delegado clásico: cree un protocolo formal y anuncie un setEventDelegate:
método. No retener al delegado. Si ni siquiera desea crear un protocolo formal, acepte un selector como devolución de llamada delegada.
Y, por último, este patrón debería hacer sonar las alarmas:
- (nulo) dealloc {
[myServerObject releaseCallbackBlocksForObject: self];
...
}
Si está tratando de desenganchar bloques que pueden referirse self
desde adentro dealloc
, ya está en problemas. dealloc
Es posible que nunca se llame debido al ciclo de retención causado por las referencias en el bloque, lo que significa que su objeto simplemente se filtrará hasta que el objeto del servidor se desasigne.
self
representantesthis
solo para cambiar las cosas. En JavaScript llamo a misthis
cierresself
, por lo que se siente agradable y equilibrado. :)