Что такое closure и зачем они нужны? Чем отличаются от func?ios-17

Определение

Closure (замыкание) - это автономный блок функциональности, который может быть передан и использован в вашем коде. По сути, это функция без имени, которая может захватывать константы и переменные из окружающего контекста.

Базовый синтаксис

// Полная форма
let sum = { (a: Int, b: Int) -> Int in
    return a + b
}

// Сокращенная форма
let sumShort: (Int, Int) -> Int = { $0 + $1 }

Основные отличия от функций

1. Синтаксис и объявление

// Функция
func multiply(a: Int, b: Int) -> Int {
    return a * b
}

// Closure
let multiplyClosure = { (a: Int, b: Int) -> Int in
    return a * b
}

2. Захват значений

Closure могут захватывать и хранить ссылки на переменные из окружающего контекста:

func makeIncrementer(incrementAmount: Int) -> () -> Int {
    var total = 0
    let incrementer: () -> Int = {
        total += incrementAmount
        return total
    }
    return incrementer
}

let incrementByTwo = makeIncrementer(incrementAmount: 2)
incrementByTwo() // 2
incrementByTwo() // 4

3. Использование в качестве аргументов

Closure часто используются для обработки завершения асинхронных операций:

func fetchData(completion: @escaping (Result<Data, Error>) -> Void) {
    URLSession.shared.dataTask(with: url) { data, response, error in
        if let error = error {
            completion(.failure(error))
        } else if let data = data {
            completion(.success(data))
        }
    }.resume()
}

Основные применения closures

  1. Асинхронные операции (колбэки, completion handlers)
  2. Высокоуровневые функции (map, filter, reduce)
    let numbers = [1, 2, 3, 4]
    let squared = numbers.map { $0 * $0 } // [1, 4, 9, 16]
    
  3. Кастомизация поведения (стратегии, сортировки)
  4. Отложенное выполнение кода
  5. Инкапсуляция связанного кода

Типы closure

  1. Non-escaping (по умолчанию) - выполняется в текущем контексте
  2. Escaping - может быть вызвано после возврата функции
  3. Autoclosure - автоматически оборачивает выражение в closure
// Escaping пример
var completions: [() -> Void] = []
func storeCompletion(_ completion: @escaping () -> Void) {
    completions.append(completion)
}

// Autoclosure пример
func logIfTrue(_ predicate: @autoclosure () -> Bool) {
    if predicate() {
        print("True")
    }
}
logIfTrue(2 > 1)

Оптимизации в Swift

  1. Нет необходимости указывать тип, если он может быть выведен
  2. Неявные возвраты для однострочных closure
  3. Сокращенные имена аргументов ($0, $1)
  4. Trailing closure синтаксис для последнего аргумента
// Trailing closure пример
UIView.animate(withDuration: 0.3) {
    self.view.alpha = 0
}

Резюмируем:

closures в Swift - это мощный инструмент для создания гибкого и модульного кода. Они отличаются от функций способностью захватывать контекст, более лаконичным синтаксисом и широким применением в асинхронных операциях и функциональном программировании. Понимание closures критически важно для современной iOS-разработки.