Kas yra išlaikymo ciklai (retain cycles) iOS?
sobes.tech AI
Atsakymas iš AI
Ciklai išlaikymo susidaro, kai du ar daugiau objektų turi stiprius ryšius vienas su kitu, sudarydami "uždarą ratą". Dėl to kiekvieno objekto nuorodų skaitiklis niekada nepasiekia nulio, ir jis negali būti atlaisvintas ARC (Automatinis nuorodų skaičiavimas). Tai sukelia atminties nutekėjimus, nes objektai lieka atmintyje net ir tada, kai jie nebenaudojami.
Pavyzdys:
class Person {
let name: String
var apartment: Apartment?
init(name: String) {
self.name = name
print("\(name) yra inicijuojamas")
}
deinit {
print("\(name) yra de-inicijuojamas")
}
}
class Apartment {
let unit: String
var tenant: Person?
init(unit: String) {
self.unit = unit
print("Apartment \(unit) yra inicijuojamas")
}
deinit {
print("Apartment \(unit) yra de-inicijuojamas")
}
}
Šiame pavyzdyje, jei Person turi stiprią nuorodą į Apartment, o Apartment turi stiprią nuorodą į Person, tada bandant atlaisvinti šiuos objektus jie nebus pašalinti, nes jų nuorodų skaitikliai nepasieks nulio.
Kaip išspręsti ciklinius ryšius:
Naudokite silpnus (weak) arba nepriklausomus (unowned) ryšius.
weak: Naudojama, kai tikėtina, kad susijęs objektas tapsnilper objekto gyvavimo ciklą. Nuoroda automatiškai tampanil, kai objektas, į kurį ji nurodo, yra atlaisvinamas. Yra pasirinktinė.unowned: Naudojama, kai žinoma, kad susijęs objektas turi tą patį arba ilgesnį gyvavimo ciklą nei objektas, turintis nuorodą į jį. Negali būtinil.
Pakeistas pavyzdys naudojant weak:
Pakeiskime tenant nuorodą Apartment klasėje į silpną:
class Apartment {
let unit: String
weak var tenant: Person? // Naudojame weak
init(unit: String) {
self.unit = unit
print("Apartment \(unit) yra inicijuojamas")
}
deinit {
print("Apartment \(unit) yra de-inicijuojamas")
}
}
Dabar, kai Person objektas atlaisvinamas, nuoroda tenant Apartment automatiškai tampa nil, nutraukdama ciklą ir leidžiant Apartment taip pat būti atlaisvintam.
Lyginamoji lentelė weak ir unowned:
| Savybė | weak |
unowned |
|---|---|---|
| Nuorodos tipas | Pasirinktinė | Pasirinktinė nėra |
Gali būti nil? |
Taip, kai objektas atlaisvinamas | Ne |
| Kada naudoti | Kai objektas gali tapti nil |
Kai objektas negali būti nil |
| Veikimas | Šiek tiek lėčiau dėl nil patikros |
Šiek tiek greičiau |
Ciklinių ryšių gali kilti ir su užklausomis (closures).
Kai užklausa įtraukia self arba savybes, ji gali sukurti stiprią nuorodą į objektą. Jei šis objektas taip pat turi stiprią nuorodą į užklausą (pvz., per savybę arba delegatą), susidaro ciklas.
Kaip išspręsti ciklinius ryšius su užklausomis:
Naudokite įrašymo sąrašą (capture list).
class SomeClass {
var value = 0
func doSomethingDelayed() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in // įrašymo sąrašas su weak self
guard let self = self else { return } // `self` patikra
self.value += 1
print("Value is now \(self.value)")
}
}
}
Šiame pavyzdyje [weak self] sukuria silpną nuorodą į self užklausos viduje, išvengiant ciklinio ryšio.