Middle
Opowiedz o liście przechwytującej w Swift.
sobes.tech AI
Odpowiedź od AI
Lista przechwytywania w Swift służy do jawnego zarządzania przechwytywaniem zmiennych przez zamknięcia (closures). Pomaga to unikać silnych cykli referencyjnych, szczególnie podczas pracy z self w zamknięciach używanych w klasach. Główne typy przechwytywania to: weak i unowned.
| Typ przechwytywania | Opis | Kiedy używać |
|---|---|---|
weak |
Przechwytuje zmienną jako opcjonalną, nie zwiększając licznika referencji. Jej wartość może stać się nil. |
Gdy obiekt zamknięcia może przetrwać obiekt przechwytywany. |
unowned |
Przechwytuje zmienną bez zwiększania licznika referencji, ale zakłada się, że obiekt przechwytywany będzie żył tak długo, jak zamknięcie. Nie jest opcjonalny. | Gdy obiekt zamknięcia i obiekt przechwytywany mają ten sam czas życia, i obiekt przechwytywany nie będzie nil przed zakończeniem zamknięcia. |
Składnia listy przechwytywania:
{ [lista przechwytywania] (parametry) -> typZwracany in
// kod
}
Przykład użycia weak self:
class MyClass {
var value = 0
func doSomethingLater() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
guard let self = self else { return } // sprawdzenie na nil
self.value += 1
print("Wartość jest teraz \(self.value)")
}
}
}
Przykład użycia unowned self:
class ViewController: UIViewController {
var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button = UIButton(type: .system)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
}
@objc func buttonTapped() {
// unowned self nie jest konieczne w tym przypadku, ponieważ button istnieje tak długo, jak istnieje ViewController.
// Ale jeśli zamknięcie mogłoby przetrwać ViewController, unowned byłoby odpowiednie, jeśli
// jest pewność, że self nie stanie się nil.
let action = { [unowned self] in
self.view.backgroundColor = .blue
}
action()
}
}
Możesz przechwycić nie tylko self, ale także dowolne inne zmienne dostępne w zamknięciu. Na przykład, aby zapisać wartość zmiennej w momencie tworzenia zamknięcia:
func createIncrementer(initialValue: Int) -> () -> Int {
var currentValue = initialValue
return { [initialValue] in // Przechwytuje initialValue jako wartość
currentValue += 1
print("Wartość początkowa to \(initialValue)") // initialValue zachowuje swoją wartość
return currentValue
}
}
let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Wydruk: Wartość początkowa to 5, potem 6
print(incrementer()) // Wydruk: Wartość początkowa to 5, potem 7