Listy przechwytywania i weak self
Unikanie cykli silnych referencji za pomocą [weak self].
Listy przechwytywania i weak self to bezpłatna lekcja Swift Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Swift Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Swift Academy zawiera 4 lekcji w sumie.
Ryzyko cyklu silnych referencji
Gdy obiekt przechowuje uciekające domknięcie, które silnie przechwytuje self, każde z nich utrzymuje drugie przy życiu na zawsze — powstaje cykl silnych referencji, powodujący wyciek pamięci.
Cykl silnych referencji
Domknięcie silnie przechwytuje self, a self przechowuje domknięcie — żaden z tych elementów nigdy nie zostaje zwolniony:
class Owner {
var onEvent: (() -> Void)?
func setup() {
onEvent = { print(self.describe()) } // strong self -> cycle
}
func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?() // "Owner" (but leaks)Listy przechwytywania
Lista przechwytywania na początku domknięcia { [weak self] in ... } określa sposób przechowywania każdego przechwyconego odwołania: jako weak lub unowned, zamiast silnego odwołania.
Przerywanie cyklu za pomocą weak self
[weak self] przechwytuje self jako wartość opcjonalną, która nie utrzymuje go przy życiu:
class Owner {
var onEvent: (() -> Void)?
func setup() {
onEvent = { [weak self] in
print(self?.describe() ?? "gone")
}
}
func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?() // "Owner" (no cycle)weak sprawia, że self jest opcjonalne
W przypadku [weak self] wartość self staje się typu Self?, więc należy ją rozpakować:
class Worker {
var tag = "W"
lazy var job: () -> Void = { [weak self] in
guard let self = self else { return }
print(self.tag)
}
}
let w = Worker()
w.job() // "W"Wzorzec guard let self
Należy ponownie przypisać self na początku, aby w pozostałej części domknięcia używać silnego, nieopcjonalnego odwołania:
class Service {
var name = "S"
lazy var run: () -> Void = { [weak self] in
guard let self else { return }
print(self.name)
print("still \(self.name)")
}
}
Service().run() // "S" / "still S"weak a unowned
weak daje wartość opcjonalną i jest bezpieczne, jeśli obiekt może już nie istnieć. unowned nie jest opcjonalne i działa szybciej, ale powoduje awarię po uzyskaniu dostępu do obiektu, który został zwolniony — należy go używać tylko wtedy, gdy ma Pan/Pani gwarancję, że self będzie istnieć dłużej niż domknięcie.
Używanie unowned
Należy wybrać unowned, gdy domknięcie nie może istnieć dłużej niż self:
class Timer2 {
var ticks = 0
lazy var tick: () -> Void = { [unowned self] in
self.ticks += 1
}
}
let t = Timer2()
t.tick(); t.tick()
print(t.ticks) // 2Przechwytywanie konkretnych właściwości
Należy przechwytywać tylko potrzebne elementy zamiast całego self — czasami pozwala to całkowicie uniknąć cyklu:
class VM {
let id = 42
lazy var printer: () -> Void = { [id] in print(id) }
}
VM().printer() // 42Domknięcia nieuciekające nie potrzebują weak
Synchroniczne domknięcia nieuciekające (takie jak map) nie powodują cykli, więc silne przechwytywanie self jest w ich przypadku bezpieczne:
class Calc {
let factor = 3
func scale(_ xs: [Int]) -> [Int] {
xs.map { $0 * self.factor } // safe, non-escaping
}
}
print(Calc().scale([1, 2])) // [3, 6]Praktyczna zasada
Należy używać [weak self] w przechowywanych lub uciekających domknięciach, które odwołują się do self. Po unowned należy sięgać tylko wtedy, gdy ma Pan/Pani gwarancję, że self będzie istnieć. W przypadku domknięć nieuciekających listy przechwytywania nie są potrzebne.
class P {
var n = "P"
var stored: (() -> Void)?
func arm() { stored = { [weak self] in print(self?.n ?? "-") } }
}
let p = P(); p.arm(); p.stored?() // "P"Szybkie sprawdzenie
Dlaczego w przechowywanym uciekającym domknięciu używa się [weak self]?
Podsumowanie
Poznał(a) Pan/Pani listy przechwytywania:
- Silne self w przechowywanym uciekającym domknięciu tworzy cykl silnych referencji (wyciek pamięci)
[weak self]przerywa cykl; self staje się opcjonalne — należy użyćguard let selfunownednie jest opcjonalne i działa szybciej, ale powoduje awarię, jeśli self już nie istnieje- Domknięcia nieuciekające nie potrzebują list przechwytywania
Dalej: autodomknięcia.
Często zadawane pytania
Czy lekcja „Listy przechwytywania i weak self” jest bezpłatna?
Tak — pełny tekst „Listy przechwytywania i weak self” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Swift Academy, przejdź na CoddyKit PRO. Kurs Swift Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Listy przechwytywania i weak self”?
Unikanie cykli silnych referencji za pomocą [weak self]. Ćwiczysz Swift Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Swift Academy?
Nie wymagamy żadnego doświadczenia. Swift Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „Listy przechwytywania i weak self”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Swift Academy?
Tak. Każda lekcja Swift Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Przechwytywanie wartości przez referencję
- Domknięcia uciekające
- Listy przechwytywania i weak self
- Autodomknięcia