Sobes.tech
Junior

Чӣ тавр аст, ки пӯшида мешавад?

sobes.tech AI

Ҷавоб аз AI

Затваряне (closure) в Swift е самодостатъчен блок от функционалност ({}), който може да бъде предаден и използван в кода. Затварянията могат да захващат и съхраняват препратки към всякакви константи и променливи от контекста, в който са дефинирани.

Примери за използване:

  • Като аргументи на функции (например, Completion Handlers).
  • За определяне на поведение при обхождане на колекции (например, използвайки методите map, filter, reduce, sorted).
  • За отложено изпълнение на код.

Синтаксис:

// Основен синтаксис
{ (параметри) -> типНаВръщане in
    изрази
}

// Пример за затваряне, което приема Int и връща String
let integerToString: (Int) -> String = { (number: Int) -> String in
    return "Число: \(number)"
}

Особености:

  • Автоматично захващане на променливи (capturing values).
  • Възможност за дефиниране на затваряния без явно указване на типове на параметрите и връщаната стойност (синтактичен захар).
  • Използване на съкратени имена на параметри ($0, $1 и др.).
  • Синтаксис на затварящия блок (trailing closure syntax).

Захващане на променливи:

Затварянето може да захване променливи от своята среда. По подразбиране захващането става по препратка. Ако затварянето се използва след като е излязла от обхвата си оригиналната променлива, затварянето все още запазва достъп до нея.

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0 // Променлива от външния контекст
    let incrementer: () -> Int = { // Затваряне
        runningTotal += amount // Захваща runningTotal и amount
        return runningTotal
    }
    return incrementer
}

let incrementByTen = makeIncrementer(forIncrement: 10)
print(incrementByTen()) // Изход: 10
print(incrementByTen()) // Изход: 20

Списъци за захващане (Capture Lists):

Използват се за явно указване как трябва да бъдат захванати променливите - по стойност или по препратка, както и за избягване на силни цикли на препратки (retain cycles).

class MyClass {
    var value = 0

    lazy var myClosure: () -> Void = { [self, value] in // Захващане на self по препратка, а value по стойност
        print("Стойност на self.value: \(self.value)")
        print("Захваната стойност: \(value)")
    }

    deinit {
        print("Обектът MyClass е освободен")
    }
}

За предотвратяване на силни цикли при захващане на обекти от класове се използва синтаксисът [weak self] или [unowned self].

class ViewController {
    var dataFetcher: DataFetcher?

    func fetchData() {
        dataFetcher?.fetch { [weak self] result in // слабо захващане на self
            guard let self = self else { return } // проверка за съществуване на self
            // обработка на резултата
        }
    }
}

class DataFetcher {
    var completionHandler: ((Result<String, Error>) -> Void)?

    func fetch(completion: @escaping (Result<String, Error>) -> Void) {
        self.completionHandler = completion
        // Асимхронна операция...
    }
}