Swift usa esta característica para administrar la memoria de las respectivas tareas dentro de tu código, no es necesario que tú como programador te preocupes por esto pues el lenguaje lo hace por sí solo.
El Reference Counting sólo aplican para clases, las estructuras y los enumeradores usan tipos de valores, no tipos de referencias, por ende no son almacenadas ni transmitidas por referencia
¿CÓMO FUNCIONA?
Cuando creas una nueva instancia de una clase, ARC almacena un bloque de memoria para la información de esa instancia junto con los valores y propiedades de la misma. Cuando esa instancia no se necesita nunca más, ARC libera la memoria para que otra clase con otras propiedades y valores pueda hacer uso de ese mismo bloque. Así que si ARC libera esa memoria para una clase que sigue en uso, ya no podrás tener acceso (es decir, la aplicación) a esas propiedades, esto hará que la app crasheé.
Para que ARC se asegure de que esa instancia va a seguir siendo utilizada, hace un conteo de cuantas propiedades, valores, entre otras, estén haciendo referencias a ella, de esa manera si al menos una sigue haciendo referencia, ARC no va a liberar el bloque de memoria de esa instancia. Por ello, siempre que asignas una instancia de alguna clase a una constante, variable y/o propiedad, esa constante, variable y/o propiedad va a hacer una strong reference, (referencia fuerte) a esa instancia.
Strong Reference
Se le llama así a este tipo de referencia porque esa información mantiene un firme agarre a la instancia y ARC no va a desalojar memoria de esta hasta que ese “firme agarre” se termine.
VEAMOS UN EJEMPLO
classPerson{
let name: Stringinit(name: String) {
self.name = name
print("\(name) is being initialized")
}
deinit {
print("\(name) is being deinitialized")
}
}
Aquí tenemos una clase llamada Person, si nosotros ahora creamos tres variables del tipo Person
var reference1: Person?
var reference2: Person?
var reference3: Person?
Éstas variables, por ser opcionales, son incivilizadas con el valor nil, y ahora podemos hacer lo siguiente
var reference1 = Person(name: "Manu Aguilar")
//Imprime: Manu Aguilar is being initialized
Esto crea una referencia fuerte a la clase, entonces si hacemos:
var reference2 = reference1
var reference3 = reference1
Tendremos TRES referencias fuertes a la clase, ARC ya no lo desalojara, aún haciendo esto:
var reference2 = nilvar reference3 = nil
Tendríamos que hacer también
var reference1 = nil//Imprime: Manu Aguilar is being deinitialized
Para que entonces ARC desaloje la memoria.
Weak Reference
Sencillamente es una referencia que no mantiene una referencia fuerte a una instancia de la clase, estas se declaran escribiendo un weak antes de var:
weakvar
De esta manera ARC “entiende” que es una referencia débil, este comportamiento previene que esta variable se vuelva parte del ciclo de referencia fuerte, esto permite que ARC desaloje la memoria de la clase, cuando lo haga, el valor de esta variable será cambiada a nil.
WEAK EXAMPLE
Digamos que tenemos las siguientes dos clases:
classPerson{
let name = Stringinit(name: String) { self.name = name }
var apartment: Apartament?
deinit { print("\(name) is being deinitialized") }
}
classApartment{
let unit: Stringinit(unit: String) { self.unit = unit }
weakvar tenant: Person?
deinit { print("Apartment \(unit) is being deinitialized") }
}
Ahora tendrán dos referencias entre ellos, la clase persona tendrá una referencia fuerte a la clase apartamento, la clase apartamento una referencia débil a la clase persona, ahora podemos hacer:
varmanu: Person?
varunit4A: Apartment?
manu = Person(name: "Manu Aguilar")
unit4A = Apartment(unit: "4A")
manu!.apartment = unit4A
unit4A!.tenant = manu
Si nosotros hacemos nil a la variable manu entonces esta clase será deinicializada.
manu = nil//Imprime: Manu Aguilar is being deinitialized
Entonces la clase Apartment sigue siendo alojada en memoria y el ARC sólo podrá deinicializarla si hacemos esto
unit4A = nil//Imprime: unit4A is being deinitialized
UNOWNED REFERENCES
Al igual que las referencias débiles, una referencia impropia no mantiene un enlace fuerte entre la información y la instancia, pero a diferencia de ella, se mantiene hasta que la otra instancia finalice su tiempo de vida, ¿Cuál otra instancia?, la respuesta depende; la preferencia predomina en cuál de las dos tiene menos tiempo de vida, o en otro caso, si las dos tienen la misma, la que termine primero.
UNOWNED EXAMPLE … XD
Veamos ahora con un ejemplo cómo funciona
classCustomer{
let name = String?
var card = creditCard? //strong referenceinit(name: String) { self.name = name }
deinit { print("\(name) is being deinitialized") }
}
classcreditCard{
let number = UInt64//para asegurarnos que aguanta los 16 dígitosunownedlet customer: Customerinit(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit{ print("Card #\(number) is being deinitialized") }
}
Si hacemos ahora una variable así, le asignamos parámetros queda:
varmanu: Customer?
manu = Customer(name "Manu")
manu!.card = creditCard(numer: 1_234_567_890_123_456, customer: manu!)
Tenemos una referencia impropia entre cada instancia, y si malévolamente hacemos esto:
manu = nil
imprime
Manu isbeing deinitialized
Card #1234567890123456 isbeing deinitialized
Veremos que ambas fueron deinicializadas.
Strong Reference Cycle between class instance
Es básicamente un ciclo entre dos instancias de clases que se mantiene vivo siempre debido a que las referencias entre ellas son referencias fuertes, cuando creas dos clases y ambas tienen propiedades que no son unowned ni weak entonces se crea un ciclo que no se va a romper incluso si haces a ambas referencias, nulas. Si defines a una propiedad como weak o unowned entonces permites que ARC resuelva esas referencias entre instancias de clase, lo que permite deshacerse de aquellos ciclos y liberar memoria
Bueno eso es todo por mi parte espero les haya servido, falta el Reference Counting para Clousures, si les gustó hago el otro. Gracias por su atención
Excelente post! Me ayudo a aclarar los conceptos de la clase 😃
Muchas gracias, este contenido ayuda a comprender mejor estos conceptos.