Шта је затварање?
sobes.tech АИ
Одговор од АИ
Zatvaranje (closure) u Swiftu je samostalni blok funkcionalnosti ({}), koji se može preneti i koristiti u kodu. Zatvaranja mogu uhvatiti i sačuvati reference na bilo koje konstante i promenljive iz konteksta u kojem su definisane.
Primeri korišćenja:
- Kao argumenti funkcija (npr. Completion Handlers).
- Za definisanje ponašanja pri iteraciji kolekcija (npr. koristeći metode
map,filter,reduce,sorted). - Za odloženo izvršavanje koda.
Sintaksa:
// Osnovna sintaksa
{ (parametri) -> povratniTip in
izrazi
}
// Primer zatvaranja koje prima Int i vraća String
let integerToString: (Int) -> String = { (number: Int) -> String in
return "Broj: \(number)"
}
Osobine:
- Automatsko hvatanje promenljivih (capturing values).
- Mogućnost definisanja zatvaranja bez eksplicitnog navođenja tipova parametara i povratne vrednosti (sintaksički šećer).
- Korišćenje skraćenih imena parametara ($0, $1 i dr.).
- Sintaksa zatvarajuće zatvarke (trailing closure syntax).
Hvatanje promenljivih:
Zatvaranje može uhvatiti promenljive iz svog okruženja. Po default-u, hvatanje se vrši po referenci. Ako se zatvaranje koristi nakon što je originalna promenljiva izašla iz opsega, zatvaranje i dalje zadržava pristup toj promenljivoj.
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0 // Promenljiva iz spoljnog okruženja
let incrementer: () -> Int = { // Zatvaranje
runningTotal += amount // Hvata runningTotal i amount
return runningTotal
}
return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Izlaz: 10
print(incrementByTen()) // Izlaz: 20
Spiskovi hvatanja (Capture Lists):
Koriste se za eksplicitno navođenje kako promenljive treba da budu uhvaćene - po vrednosti ili po referenci, kao i za izbegavanje jakih ciklusa referenci (retain cycles).
class MyClass {
var value = 0
lazy var myClosure: () -> Void = { [self, value] in // Hvatanje self po referenci, value po vrednosti
print("Vrednost self.value: \(self.value)")
print("Uhvaćena vrednost: \(value)")
}
deinit {
print("Instanca MyClass je oslobođena")
}
}
Za sprečavanje jakih ciklusa pri hvatanju objekata klasa koristi se sintaksa [weak self] ili [unowned self].
class ViewController {
var dataFetcher: DataFetcher?
func fetchData() {
dataFetcher?.fetch { [weak self] result in // slaba referenca na self
guard let self = self else { return } // provera postojanja self
// obrada rezultata
}
}
}
class DataFetcher {
var completionHandler: ((Result<String, Error>) -> Void)?
func fetch(completion: @escaping (Result<String, Error>) -> Void) {
self.completionHandler = completion
// Asinhrona operacija...
}
}