Recherche…


Introduction

Cette rubrique décrit comment et quand le runtime Swift alloue de la mémoire pour les structures de données d'application et quand cette mémoire doit être récupérée. Par défaut, les instances de la classe de sauvegarde de la mémoire sont gérées via le comptage des références. Les structures passent toujours par la copie. Pour désactiver le schéma de gestion de la mémoire intégrée, vous pouvez utiliser la structure [ Unmanaged ] [1]. [1]: https://developer.apple.com/reference/swift/unmanaged

Remarques

Quand utiliser le mot-clé faible:

Le mot-clé weak doit être utilisé si un objet référencé peut être désalloué pendant la durée de vie de l'objet contenant la référence.

Quand utiliser le mot-clé sans propriétaire:

Le unowned clé unowned propriétaire doit être utilisé si un objet référencé n'est pas censé être désalloué pendant la durée de vie de l'objet contenant la référence.

Pièges

Une erreur fréquente est d'oublier de créer des références à des objets, qui doivent survivre à la fin d'une fonction, comme les gestionnaires de lieu, les gestionnaires de mouvement, etc.

Exemple:

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

Cet exemple ne fonctionnera pas correctement, car le gestionnaire d'emplacement est désalloué après le retour de l'initialiseur. La solution appropriée consiste à créer une référence forte en tant que variable d’instance:

class A : CLLocationManagerDelegate
{
    let locationManager:CLLocationManager

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

Cycles de référence et références faibles

Un cycle de référence (ou cycle de conservation ) est nommé ainsi car il indique un cycle dans le graphe d'objet :

conserver le cycle

Chaque flèche indique un objet en retenant un autre (une référence forte). À moins que le cycle ne soit rompu, la mémoire de ces objets ne sera jamais libérée .

Un cycle de conservation est créé lorsque deux instances de classes se réfèrent l'une à l'autre:

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

Les deux instances resteront en vie jusqu'à la fin du programme. Ceci est un cycle de rétention.

Références faibles

Pour éviter les cycles de rétention, utilisez le mot-clé weak ou sans unowned lors de la création de références pour les cycles de retenue.

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

Des références faibles ou non acquises n'augmenteront pas le nombre de références d'une instance. Ces références ne contribuent pas à conserver les cycles. La référence faible devient nil lorsque l'objet référencé est désalloué.

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

Lorsque vous travaillez avec des fermetures, vous pouvez également utiliser weak listes de capture weak ou unowned .

Gestion de la mémoire manuelle

Lors de l’interfaçage avec les API C, il est possible de désactiver le compteur de référence Swift. Cela se fait avec des objets non gérés.

Si vous devez fournir un pointeur de type puned à une fonction C, utilisez la méthode toOpaque de la structure Unmanaged pour obtenir un pointeur brut et fromOpaque pour récupérer l'instance d'origine:

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()
}

Notez que si vous utilisez passUnretained et ses homologues, il est nécessaire de prendre toutes les précautions comme avec les références non- unowned .

Pour interagir avec les API Objective-C héritées, il peut être nécessaire d'affecter manuellement le nombre de références d'un objet donné. Pour cela, Unmanaged a retain et release méthodes respectives. Néanmoins, il est passRetained utiliser passRetained et takeRetainedValue , qui effectuent des conservations avant de renvoyer le résultat:

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

  return result!.takeRetainedValue() as String
}

Ces solutions doivent toujours être le dernier recours et les API natives doivent toujours être préférées.



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow