ARC (Automatic Reference Counting) — system automatycznego zarządzania pamięcią w Swift. Przy każdym nowym silnym wskaźniku do obiektu licznik zwiększa się; przy usunięciu — zmniejsza. Kiedy licznik wynosi zero — obiekt jest zwalniany.
Retain cycle (cykl zatrzymywania) — sytuacja, w której obiekty odwołują się do siebie silnymi referencjami i nigdy nie są zwalniane.
Sposoby uniknięcia:
protocol SomeDelegate: AnyObject { } class Owner { weak var delegate: SomeDelegate? }
[weak self] lub [unowned self]:class Example { var closure: (() -> Void)? func setup() { closure = { [weak self] in self?.doSomething() } } func doSomething() { } }
Jaka jest różnica między [weak self] a [unowned self] w obrębie closure? Kiedy używać jakiego typu referencji?
Odpowiedź:
[weak self] tworzy opcjonalną referencję; self może być nil, więc zazwyczaj stosuje się bezpieczne wydobywanie self?.[unowned self] tworzy nie-opcjonalną referencję i NIE zwiększa licznika; jeśli obiekt został już zwolniony i następuje odwołanie — dojdzie do awarii.[unowned self].Przykład:
someClosure = { [weak self] in self?.doTask() } // lub (jeśli self 100% żyje dłużej niż closure): someClosure = { [unowned self] in doTask() }
Historia
W projekcie powstała sytuacja cyklu zatrzymywania między ViewController a jego closure, związanym z obsługą kliknięcia. ViewController odnosił się do closure, które przechwytywało self silną referencją. W rezultacie, kontroler i wszystkie jego dane nie były zwalniane po zamknięciu ekranu. Problem rozwiązano poprzez wprowadzenie
[weak self]w closure.
Historia
Implementacja wzorca delegata między dwoma obiektami. Delegat został zadeklarowany jako silna (
strong) właściwość. W rezultacie przy próbie usunięcia głównego obiektu z pamięci nie został on zwolniony, co doprowadziło do wycieku pamięci. Po przejściu delegata na weak problem zniknął.
Historia
Do animacji używano closure wewnątrz UIView. Closure przechwytywało self za pomocą
[unowned self]. Gdy widoki były usuwane przed zakończeniem animacji, aplikacja ulegała awarii z powodu odwołania się do już zwolnionego self. Rozwiązanie — użycie[weak self]i obowiązkowe sprawdzenie, czy self nie jest nil wewnątrz closure.