Sobes.tech
Middle

Povedz mi o capture list v Swift-u.

sobes.tech AI

Odpoveď od AI

V Swift sa používa capture list na explicitnú správu zachytávania premenných v uzávierkach (closures). To pomáha vyhnúť sa silným cyklom odkazov, najmä pri práci s self vo vnútri uzávierok používaných v triedach. Hlavné typy zachytenia sú: weak a unowned.

Typ zachytenia Popis Kedy použiť
weak Zachytáva premennú ako voliteľnú, nezvyšuje počet odkazov. Jej hodnota môže byť nil. Keď objekt uzávierky môže prežiť zachytený objekt.
unowned Zachytáva premennú bez zvýšenia počtu odkazov, ale predpokladá sa, že zachytený objekt bude žiť, kým existuje uzávierka. Nie je voliteľný. Keď má uzávierka a zachytený objekt rovnakú dobu života a zachytený objekt nebude nil pred ukončením uzávierky.

Syntax capture list:

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

Príklad použitia 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 teraz \(self.value)")
        }
    }
}

Príklad použitia 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 je potrebné v tomto prípade, pretože button existuje, kým existuje ViewController.
        // Ale ak by uzávierka mohla prežiť ViewController, unowned by mohol byť vhodný, ak sme si istí,
        // že self nebude `nil`.
        let action = { [unowned self] in
             self.view.backgroundColor = .blue
        }
        action()
    }
}

Zachytávať možno nielen self, ale aj akékoľvek iné premenné dostupné v uzávierke. Napríklad, aby ste zachovali hodnotu premennej v momente vytvorenia uzávierky:

func createIncrementer(initialValue: Int) -> () -> Int {
    var currentValue = initialValue
    return { [initialValue] in // Zachytávame initialValue podľa hodnoty
        currentValue += 1
        print("Počiatočná hodnota bola \(initialValue)") // initialValue si zachová svoju hodnotu
        return currentValue
    }
}

let incrementer = createIncrementer(initialValue: 5)
print(incrementer()) // Výstup: Počiatočná hodnota bola 5, potom 6
print(incrementer()) // Výstup: Počiatočná hodnota bola 5, potom 7