Sobes.tech
Middle

Pověz mi o seznamu zachycení v Swift.

sobes.tech AI

Odpověď od AI

V Swiftu se používá capture list pro explicitní správu zachycení proměnných uzávěry (closures). To pomáhá zabránit silným cyklům odkazů, zejména při práci s self uvnitř uzávěrů používaných ve třídách. Hlavní typy zachycení: weak a unowned.

Typ zachycení Popis Kdy použít
weak Zachytí proměnnou jako volitelnou, nezvyšuje počítadlo odkazů. Její hodnota může být nil. Když objekt uzávěru může přežít zachycený objekt.
unowned Zachytí proměnnou bez zvýšení počítadla odkazů, ale předpokládá se, že zachycený objekt bude žít, dokud existuje uzávěr. Není volitelný. Když mají uzávěr a zachycený objekt stejnou dobu života a zachycený objekt nebude nil do ukončení uzávěru.

Syntaxe capture list:

{ [capture list] (parametry) -> návratový typ in
    // kód
}

Příklad použití weak self:

class MyClass {
    var value = 0

    func doSomethingLater() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [weak self] in
            guard let self = self else { return } // Kontrola na nil
            self.value += 1
            print("Hodnota je nyní \(self.value)")
        }
    }
}

Příklad použití 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 není v tomto případě potřeba, protože button existuje, dokud existuje ViewController.
        // Ale pokud by uzávěr mohl přežít ViewController, mohl by být vhodný unowned, pokud si jsme jisti,
        // že self nebude `nil`.
        let action = { [unowned self] in
             self.view.backgroundColor = .blue
        }
        action()
    }
}

Zachytit lze nejen self, ale i jiné proměnné dostupné v uzávěru. Například, aby se zachovala hodnota proměnné v okamžiku vytvoření uzávěru:

func createIncrementer(initialValue: Int) -> () -> Int {
    var currentValue = initialValue
    return { [initialValue] in // Zachytíme initialValue podle hodnoty
        currentValue += 1
        print("Původní hodnota byla \(initialValue)") // initialValue si zachová svou hodnotu
        return currentValue
    }
}

let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Výstup: Původní hodnota byla 5, pak 6
print(incrementer()) // Výstup: Původní hodnota byla 5, pak 7