Sobes.tech
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