Sobes.tech
Junior

Шта је затварање?

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...
    }
}