Sobes.tech
Middle

Hoe kun je een retain cycle voorkomen in iOS?

sobes.tech AI

Antwoord van AI

Cycli van vasthouden worden voorkomen door correct gebruik van zwakke (weak) of onvoorwaardelijke (unowned) referenties.

Zwakke referenties (weak):

  • Verhogen de referentieteller niet.
  • Kunnen nil worden (nullable).
  • Worden gebruikt wanneer een object onafhankelijk van een ander kan bestaan (bijvoorbeeld, een delegate).
class DelegateExample {
    weak var delegate: SomeDelegateType? // Zwakke referentie naar delegate
}

Onvoorwaardelijke unowned referenties (unowned):

  • Verhogen de referentieteller niet.
  • Zijn gegarandeerd niet null.
  • Worden gebruikt wanneer een object expliciet een ander bezit, maar het afhankelijke object alleen samen met de eigenaar kan bestaan (bijvoorbeeld, closures die self capturen in een klasse, waar de closure expliciet toebehoort aan de instantie van de klasse). Toegang tot een unowned referentie wanneer het object al is vrijgegeven, veroorzaakt een runtime-fout.
class Owner {
    var closure: (() -> Void)?

    func setupClosure() {
        closure = { [unowned self] in // Onvoorwaardelijke `unowned` referentie naar self
            // Gebruik van self
            print("Gebruik van onunowned self")
        }
    }
}

Gebruik in closures: Closures kunnen cycli van vasthouden creëren als ze instanties van klassen capturen via sterke referenties, en die klasse bevat ook een sterke referentie naar het closure. Om dit te voorkomen, worden capture-lijsten (capture lists) aan het begin van het closure gebruikt:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { [weak self] in // Zwakke referentie naar self
        guard let strongSelf = self else {
            return "" // Afhandeling van het geval dat self al nil is
        }
        if let text = strongSelf.text {
            return "<\(strongSelf.name)>\(text)</\(strongSelf.name)>"
        } else {
            return "<\(strongSelf.name)/>"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) wordt gedeinitialiseerd")
    }
}

De keuze tussen weak en unowned hangt af van de semantiek van de relaties tussen objecten:

  • weak: wanneer de referentie in de levenscyclus van het object dat wordt verwezen, nil kan worden.
  • unowned: wanneer het verweesde object gegarandeerd langer of gelijk lang bestaat als het object dat het verwijst, en de referentie nooit nil wordt.