Где это используется?
Closures становится частью настоящего интерфейса уже в первых проектах.
- Project 1 — WeSplit →Приложение для разделения счёта между людьми и расчёта чаевых.
- Project 2 — Guess the Flag →Игра-викторина: выбери правильный флаг и получи обратную связь.
- Project 3 — Views and Modifiers →Разбор composition, custom modifiers и того, как SwiftUI строит интерфейс.
День 9 — Замыкания
Closure (замыкание) — функция, которую можно сохранить в переменную или передать как значение. В SwiftUI замыкания встречаются повсюду: внутри Button, при построении списка и при обработке событий.
Функция в переменной
Обычную функцию можно сохранить без вызова — без круглых скобок.
func greetUser() {
print("Привет!")
}
let action = greetUser
action()Тип action — () -> Void: она не принимает параметров и ничего не возвращает.
Closure expression
Ту же функцию можно записать прямо в фигурных скобках.
let greetUser = {
print("Привет!")
}
greetUser()Параметры и return type находятся внутри скобок перед словом in.
let greet = { (name: String) -> String in
"Привет, \(name)!"
}
print(greet("Лена"))in отделяет описание входа и выхода от тела замыкания.
Передача closure в функцию
Функция может принять поведение как параметр.
func perform(_ action: () -> Void) {
print("Начало")
action()
print("Конец")
}
perform({
print("Работа выполняется")
})Тип () -> Void означает «замыкание без параметров и результата».
Сортировка с sorted(by:)
Array знает, как сортировать стандартные типы по возрастанию. Замыкание позволяет задать другое правило.
let team = ["Мария", "Анна", "Александр", "Илья"]
let captainFirst = team.sorted { first, second in
if first == "Анна" {
return true
} else if second == "Анна" {
return false
}
return first < second
}Замыкание получает два элемента и возвращает true, если первый должен стоять раньше второго.
Сокращённые имена параметров
Swift умеет вывести типы и предлагает $0, $1 для параметров.
let reverse = team.sorted { $0 > $1 }Короткая форма хороша для одного ясного выражения. В сложной логике имена first и second читаются лучше.
Trailing closures
Если последний параметр функции — closure, его можно вынести после скобок. Это называется trailing closure syntax.
func makeAnimation(duration: Double, changes: () -> Void) {
print("Анимация: \(duration) сек.")
changes()
}
makeAnimation(duration: 0.3) {
print("Меняем интерфейс")
}Именно поэтому SwiftUI-код выглядит как вложенная структура:
// Пример формы API SwiftUI:
// Button("Сохранить") {
// saveDocument()
// }filter и map
filter оставляет элементы, для которых closure вернул true.
let numbers = [1, 2, 3, 4, 5, 6]
let even = numbers.filter { $0.isMultiple(of: 2) }map преобразует каждый элемент и возвращает новый Array.
let labels = numbers.map { "Число: \($0)" }Исходный массив при этом не меняется.
Несколько closure-параметров
Современный Swift позволяет подписать несколько trailing closures.
func loadData(success: (String) -> Void, failure: () -> Void) {
let loaded = true
if loaded {
success("Готово")
} else {
failure()
}
}
loadData { message in
print(message)
} failure: {
print("Ошибка загрузки")
}Глубже: @Sendable
@Sendable и конкурентный код
Closure, который может выполняться параллельно с другим кодом, часто помечается @Sendable. Компилятор Swift 6 проверяет, что такой closure не захватил небезопасное изменяемое состояние.
let makeMessage: @Sendable (String) -> String = { name in
"Готово, \(name)"
}Пока достаточно узнавать эту аннотацию. После первого async/await-проекта тема продолжится в Actors и Sendable.
Checkpoint
Условие
Есть массив let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]. Одной цепочкой отфильтруйте чётные числа, отсортируйте оставшиеся по возрастанию, преобразуйте их в строки вида 7 — счастливое число, затем напечатайте каждую строку.
Что нужно знать
filter,sorted,map;- сокращённые параметры
$0; - цепочка преобразований;
forдля вывода.
Показать подсказку
Каждый метод возвращает новый Array, поэтому после закрывающей скобки можно сразу вызвать следующий метод.
Показать решение
let luckyNumbers = [7, 4, 38, 21, 16, 15, 12, 33, 31, 49]
let messages = luckyNumbers
.filter { !$0.isMultiple(of: 2) }
.sorted()
.map { "\($0) — счастливое число" }
for message in messages {
print(message)
}Что запомнить
Closure — обычное значение с функциональным типом. Сокращайте синтаксис только пока смысл остаётся очевидным.
Комментарии
Вопросы, находки и подсказки по этой странице.
Войди, чтобы задать вопрос или помочь другим.