[OC Combing] Referencias circulares y sus soluciones
Un ejemplo simple:
El objeto A contiene el objeto B, el objeto B contiene el objeto C y el objeto C contiene el objeto A. En este momento, se forma una referencia entre los dos. :
En este momento, si hay un objeto D que hace referencia al objeto A, debido a la referencia circular entre ABC, sus contadores de referencia son los siguientes:
Entonces incluso si D libera el objeto A. Los contadores de referencia de A, B y C siguen siendo 1 y no se liberarán ni reciclarán.
Debido a la existencia de referencias circulares, los objetos que generan referencias circulares siempre ocupan espacio en la memoria. Demasiadas referencias circulares harán que el uso de memoria del programa aumente, lo que eventualmente conducirá al programa Creach.
Utilice débil en lugar de fuerte para resolver este problema:
La referencia circular del bloque ocurre principalmente cuando el bloque se guarda en ViewController, por ejemplo:
Al mismo tiempo, cuando se asigna un callbackBlock, se llamará al método ViewController, por ejemplo:
Se producirá una referencia circular porque: controlador de vista-->;devolución de llamada fuertemente referenciada->>ViewController está fuertemente referenciado, la solución es simple:
p>¿Todos los bloques tienen referencias circulares? De hecho, este no es el caso. Por ejemplo, la animación del bloque del método de clase de UIView y el método de recorrido de clase de NSArray no tendrán referencias circulares, porque el controlador actual generalmente no tiene una referencia fuerte a una clase.
NSTimer es un ejemplo de referencia circular que fácilmente se pasa por alto.
Porque el temporizador tendrá una fuerte referencia a uno mismo, y el propio temporizador retiene el temporizador, provocando una referencia circular.
¿Se puede solucionar con punteros débiles como Block? Por ejemplo
Pero en realidad es inútil, porque ya sea débil o fuerte, eventualmente se regenerará un nuevo puntero a Self dentro de NSTimer. Este puntero es un puntero de referencia fuerte, lo que conducirá a una referencia circular. .
¿Cómo solucionarlo? Usar NSProxy es una forma brutalmente sencilla.
NSProxy en sí es una clase abstracta que sigue el protocolo NSObject y proporciona una interfaz común para el reenvío de mensajes. NSProxy se utiliza normalmente para implementar mecanismos de reenvío de mensajes e inicialización diferida de recursos.
Para usar NSProxy, necesita escribir una subclase para heredarla y luego implementar métodos relacionados con init y reenvío de mensajes:
Al crear un NSTimer, utilice lo siguiente métodos:
El principio es el siguiente:
Convierta la línea de puntos en una referencia débil. Entonces, se puede liberar el controlador. Llamamos invalid en el reparto del controlador, rompiendo la referencia del Runloop al Timer, por lo que se liberan los tres celestes.
Artículo de referencia: NSProxy y mecanismo de reenvío de mensajes