Parlez-nous de la gestion de la mémoire dans iOS.
sobes.tech IA
Réponse de l'IA
iOS utilise le comptage automatique des références (ARC) pour gérer la mémoire. ARC libère automatiquement les objets dès qu'ils ne sont plus référencés.
Concepts principaux:
- Référence forte: Augmente le compteur de références de l'objet. L'objet ne sera pas libéré tant qu'il existe des références fortes.
- Référence faible: N'augmente pas le compteur de références. Utilisée pour prévenir les cycles de références fortes. Fait référence à un objet qui peut être libéré. Si l'objet est libéré, la référence faible devient
nil. - Référence non possédée (unowned): Semblable à faible, n'augmente pas le compteur de références. Utilisée lorsque l'objet référencé a un cycle de vie égal ou plus long. La référence non possédée ne devient pas
nillors de la libération de l'objet. Tenter d'accéder à un objet libéré via une référence non possédée génère une erreur d'exécution.
Cycles de références fortes (Retain Cycles): Se produisent lorsque deux ou plusieurs objets se référencent mutuellement avec des références fortes, empêchant leur libération. Résolus en utilisant des références faibles ou non possédées.
Exemple de cycle de références fortes et sa solution:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) est en cours d'initialisation")
}
deinit {
print("\(name) est en cours de désinitialisation")
}
}
class Apartment {
let unit: String
var tenant: Person? // Référence forte causant un cycle de rétention
init(unit: String) {
self.unit = unit
print("Appartement \(unit) est en cours d'initialisation")
}
deinit {
print("Appartement \(unit) est en cours de désinitialisation")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john // Cycle de rétention ici
john = nil
unit4A = nil
// Les méthodes de désinitialisation ne sont pas appelées en raison du cycle de rétention
Solution avec weak:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) est en cours d'initialisation")
}
deinit {
print("\(name) est en cours de désinitialisation")
}
}
class Apartment {
let unit: String
weak var tenant: Person? // Utilisation de référence weak pour éviter le cycle de rétention
init(unit: String) {
self.unit = unit
print("Appartement \(unit) est en cours d'initialisation")
}
deinit {
print("Appartement \(unit) est en cours de désinitialisation")
}
}
var john: Person? = Person(name: "John Appleseed")
var unit4A: Apartment? = Apartment(unit: "4A")
john!.apartment = unit4A
unit4A!.tenant = john
john = nil
unit4A = nil
// Les deux objets sont correctement désinitialisés
Non possédé (unowned) vs Faible (weak):
- Utilise
weaklorsque la référence peut devenirnil(l'objet peut être libéré en premier). - Utilise
unownedlorsque la référence aura toujours une valeur (l'objet référencé a un cycle de vie égal ou plus long).
Closures et cycles de références:
Les closures peuvent capturer des références à des objets, créant des cycles de références fortes. Cela se résout avec une liste de capture (capture list).
Exemple:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[weak self] in // Capture weak self
guard let self = self else {
return ""
}
var html = "<\(self.name)"
if let text = self.text {
html += ">\(text)</\(self.name)>"
} else {
html += " />"
}
return html
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
print("\(name) est en cours de désinitialisation")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "bonjour, monde")
print(paragraph!.asHTML())
paragraph = nil
// L'objet est désinitialisé
Débogage des problèmes de mémoire:
- Memory Graph Debugger: Dans Xcode, permet de visualiser les connexions entre objets et de détecter les cycles de références fortes.
- Instruments (Allocations, Leaks): Outils pour surveiller l'allocation et la libération de mémoire, et détecter les fuites.