Sobes.tech
Middle

Mis on hoidmis- (retain) tsüklid iOS-is?

sobes.tech AI

Vastus AI-lt

Atkārtojuma cikli veidojas, kad divi vai vairāki objekti ir stipri saistīti viens ar otru, radot "aizvērto loku". Rezultātā katra objekta atsauces skaitītājs nekad nesasniedz nulli, un tas nevar tikt atbrīvots ar ARC (Automātisko atsauču skaitīšanu). Tas noved pie atmiņas noplūdēm, jo objekti paliek atmiņā pat tad, kad tie vairs netiek izmantoti.

Piemērs:

class Person {
    let name: String
    var apartment: Apartment?

    init(name: String) {
        self.name = name
        print("\(name) tiek inicializēts")
    }

    deinit {
        print("\(name) tiek de-inicializēts")
    }
}

class Apartment {
    let unit: String
    var tenant: Person?

    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) tiek inicializēts")
    }

    deinit {
        print("Apartment \(unit) tiek de-inicializēts")
    }
}

Šajā piemērā, ja Person ir stipra saite uz Apartment, un Apartment ir stipra saite uz Person, tad, mēģinot atbrīvot šos objektus, tie netiks izņemti, jo to atsauces skaitītāji nekad nesasniedz nulli.

Kā novērst cikliskās saites:

Izmantojiet vagas (weak) vai neapzinātas (unowned) saites.

  • weak: Izmanto, kad ir iespējams, ka saistītais objekts kļūs nil dzīves laikā. Atsauce automātiski kļūst nil, kad objekts, uz kuru tā norāda, tiek atbrīvots. Ir opcionala.
  • unowned: Izmanto, kad ir zināms, ka saistītais objekts ir tāds pats vai ilgāks dzīves cikls nekā objekts, kam ir atsauce uz to. Nav nil.

Labots piemērs ar weak:

Mainīsim tenant saiti Apartment klasē uz vājo:

class Apartment {
    let unit: String
    weak var tenant: Person? // Izmanto `weak`

    init(unit: String) {
        self.unit = unit
        print("Apartment \(unit) tiek inicializēts")
    }

    deinit {
        print("Apartment \(unit) tiek de-inicializēts")
    }
}

Dabar, kad Person objekts tiek atbrīvots, saite tenant Apartment automātiski kļūst nil, pārtraucot ciklu un ļaujot Apartment arī tikt atbrīvotam.

Salīdzināšanas tabula weak un unowned:

Raksturlielums weak unowned
Saite tips Opcionala Opcionala nav
Var būt nil? Jā, kad objekts tiek atbrīvots
Kada lietot Kad objekts var kļūt nil Kad objekts nevar būt nil
Veiktspēja Nedaudz lēnāk dēļ nil pārbaudes Nedaudz ātrāk

Cikliskās saites var rasties arī ar slēdzieniem (closures).

Kad slēdzis iekļauj instance īpašības vai self, tas var radīt stipru saiti uz objektu. Ja šis objekts arī stipri saistīts ar slēdzi (piemēram, caur īpašību vai deleģentu), veidojas cikls.

Kā novērst cikliskās saites ar slēdzieniem:

Izmantojiet uzturēšanas sarakstu (capture list).

class SomeClass {
    var value = 0

    func doSomethingDelayed() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in // uzturēšanas saraksts ar weak self
            guard let self = self else { return } // `self` pārbaude
            self.value += 1
            print("Value is now \(self.value)")
        }
    }
}

Šajā piemērā [weak self] izveido vājo saiti uz self slēdziena iekšpusē, novēršot ciklisko saiti.