Buscar..


Introducción

Este tema describe cómo y cuándo el tiempo de ejecución de Swift asignará memoria para las estructuras de datos de la aplicación y cuándo se recuperará esa memoria. De forma predeterminada, las instancias de la clase de respaldo de memoria se administran a través del conteo de referencias. Las estructuras se pasan siempre a través de la copia. Para excluirse del esquema de administración de memoria incorporado, se podría usar la estructura [ Unmanaged ] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged

Observaciones

Cuándo usar la palabra clave débil:

La palabra clave weak debe usarse, si un objeto referenciado puede ser desasignado durante la vida útil del objeto que contiene la referencia.

Cuándo usar la palabra clave sin dueño:

Se debe usar la palabra clave unowned propietario, si no se espera que un objeto referenciado se desasigne durante la vida útil del objeto que contiene la referencia.

Escollos

Un error frecuente es olvidarse de crear referencias a objetos, que se requieren para vivir después de que finaliza una función, como administradores de ubicación, administradores de movimiento, etc.

Ejemplo:

class A : CLLocationManagerDelegate
{
    init()
    {
        let locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.startLocationUpdates()
    }
}

Este ejemplo no funcionará correctamente, ya que el administrador de ubicación se desasigna una vez que el inicializador regresa. La solución adecuada es crear una referencia fuerte como una variable de instancia:

class A : CLLocationManagerDelegate
{
    let locationManager:CLLocationManager

    init()
    {
        locationManager = CLLocationManager()
        locationManager.delegate = self
        locationManager.startLocationUpdates()
    }
}

Ciclos de referencia y referencias débiles

Un ciclo de referencia (o ciclo de retención ) se llama así porque indica un ciclo en el gráfico de objetos :

ciclo de retención

Cada flecha indica un objeto que retiene otro (una referencia fuerte). A menos que el ciclo se rompa, la memoria de estos objetos nunca se liberará .

Se crea un ciclo de retención cuando dos instancias de clases se hacen referencia:

class A { var b: B? = nil }
class B { var a: A? = nil }

let a = A()
let b = B()

a.b = b  // a retains b
b.a = a  // b retains a -- a reference cycle

Ambas instancias vivirán hasta que el programa termine. Este es un ciclo de retención.

Referencias débiles

Para evitar los ciclos de retención, use la palabra clave weak o unowned al crear referencias para romper los ciclos de retención.

class B { weak var a: A? = nil }

Las referencias débiles o sin propiedad no aumentarán el recuento de referencias de una instancia. Estas referencias no contribuyen a retener los ciclos. La referencia débil se vuelve nil cuando el objeto al que hace referencia se desasigna.

a.b = b  // a retains b
b.a = a  // b holds a weak reference to a -- not a reference cycle

Cuando trabaje con cierres, también puede usar weak y unowned en las listas de captura .

Gestión de memoria manual

Al interactuar con las API de C, es posible que desee retroceder el contador de referencia de Swift. Al hacerlo se logra con objetos no gestionados.

Si necesita suministrar un puntero de tipo punted a una función C, use el método de toOpaque de la estructura no Unmanaged para obtener un puntero sin fromOpaque y de fromOpaque para recuperar la instancia original:

setupDisplayLink() {
  let pointerToSelf: UnsafeRawPointer = Unmanaged.passUnretained(self).toOpaque()
  CVDisplayLinkSetOutputCallback(self.displayLink, self.redraw, pointerToSelf)
}

func redraw(pointerToSelf: UnsafeRawPointer, /* args omitted */) {
  let recoveredSelf = Unmanaged<Self>.fromOpaque(pointerToSelf).takeUnretainedValue()
  recoveredSelf.doRedraw()
}

Tenga en cuenta que, si utiliza passUnretained y sus homólogos, es necesario tomar todas las precauciones como con las referencias unowned .

Para interactuar con las API heredadas de Objective-C, uno podría querer afectar manualmente el conteo de referencias de un determinado objeto. Para eso Unmanaged tiene métodos respectivos de retain y release . No obstante, es más deseable usar passRetained y takeRetainedValue , que realizan la retención antes de devolver el resultado:

func preferredFilenameExtension(for uti: String) -> String! {
  let result = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension)
  guard result != nil else { return nil }

  return result!.takeRetainedValue() as String
}

Estas soluciones siempre deben ser el último recurso, y las API nativas de idioma siempre deben ser preferidas.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow