Где это используется?
Optionals становится частью настоящего интерфейса уже в первых проектах.
- Project 1 — WeSplit →Приложение для разделения счёта между людьми и расчёта чаевых.
- Project 4 — BetterRest →Подбор времени сна с помощью формы, Date и модели Create ML.
- Project 5 — Word Scramble →Игра со словами, списками, проверкой ввода и системным словарём.
День 14 — Optionals
Optional (опциональное значение) отвечает на вопрос: «значение есть или его нет?». Это не специальное пустое число и не строка. Optional хранит либо значение конкретного типа, либо nil.
Создание optional
var username: String? = "Анна"
username = nilString? и String — разные типы. Перед использованием optional нужно безопасно извлечь значение, потому что его может не быть.
let number = Int("42") // Int?
let invalid = Int("Swift") // nilПреобразование строки возвращает optional: не любая строка является числом.
if let
Optional binding временно извлекает значение, если оно существует.
let name: String? = "Лена"
if let name = name {
print("Привет, \(name)")
} else {
print("Имя не указано")
}В современном Swift при одинаковом имени запись сокращается:
if let name {
print(name.uppercased())
}Можно извлечь несколько значений и добавить условие.
let email: String? = "mail@example.com"
let age: Int? = 20
if let email, let age, age >= 18 {
print("\(email): доступ разрешён")
}guard let
guard let проверяет обязательное условие и требует выйти из текущей области, если оно не выполнено.
func greet(_ name: String?) {
guard let name else {
print("Имя отсутствует")
return
}
print("Привет, \(name)!")
}После guard извлечённое значение доступно до конца функции. Это помогает обработать ошибки в начале и оставить основной путь без лишней вложенности.
Nil coalescing
Оператор ?? подставляет запасное значение, если optional равен nil.
let savedName: String? = nil
let displayName = savedName ?? "Гость"Правый операнд должен иметь тот же базовый тип: для String? запасное значение — String.
let input = "не число"
let value = Int(input) ?? 0Используйте fallback, только когда он имеет честный смысл. Иногда 0 скрывает ошибочный ввод, и лучше показать сообщение.
Optional chaining
?. вызывает property или method, только если значение существует.
let names = ["Анна", "Борис"]
let firstLetter = names.first?.uppercased()Если Array пуст, вся цепочка вернёт nil. Можно сразу добавить fallback.
let result = names.first?.uppercased() ?? "НЕТ ИМЕНИ"Цепочка может быть длиннее:
struct Address {
let city: String
}
struct User {
let address: Address?
}
let user: User? = User(address: Address(city: "Казань"))
let city = user?.address?.city ?? "Город не указан"try?
try? превращает результат throwing function в optional. Успех даёт значение, ошибка — nil.
enum LoadError: Error { case missing }
func loadName() throws -> String {
throw LoadError.missing
}
let loadedName = try? loadName()Используйте try?, когда важен только факт успеха. Если нужно объяснить причину пользователю, выберите do/catch.
Force unwrap: !
value! извлекает optional без проверки и аварийно завершает программу при nil.
let number = Int("42")!В этом литеральном примере значение очевидно, но привычка к ! опасна. В реальном вводе, сети и файлах данные меняются. Предпочитайте if let, guard let или ??.
Optional как enum
Упрощённо String? можно представить так:
enum OptionalString {
case none
case some(String)
}Это помогает понять, почему значение нельзя использовать до извлечения: оно находится внутри одного из вариантов enum.
Checkpoint
Условие
Напишите функцию, которая принимает optional Array целых чисел и возвращает случайный элемент. Если Array отсутствует или пуст, верните случайное число от 1 до 100. Попробуйте выразить результат одной строкой.
Что нужно знать
- optional parameter;
- optional chaining;
randomElement()возвращает optional;- nil coalescing
??.
Показать подсказку
Цепочка numbers?.randomElement() даст nil, если нет Array или в нём нет элементов. После неё можно поставить ??.
Показать решение
func randomNumber(from numbers: [Int]?) -> Int {
numbers?.randomElement() ?? Int.random(in: 1...100)
}
print(randomNumber(from: [10, 20, 30]))
print(randomNumber(from: nil))Что запомнить
Optional заставляет явно обработать отсутствие данных. Это не помеха, а защита от целого класса ошибок с null references.
map, flatMap и два уровня отсутствия
Optional map преобразует wrapped value, не раскрывая его вручную:
let nickname: String? = "swiftie"
let label: String? = nickname.map { "@\($0)" }Если closure сама возвращает Optional, flatMap не создаёт вложенный T??. Но обычный if let лучше, когда есть несколько шагов или отдельная ветка ошибки.
T?? иногда несёт реальный смысл: внешнее nil может означать «запись не найдена», а внутреннее — «запись есть, поле не заполнено». Не сворачивайте эти состояния в одно, если интерфейс должен различать их.
Комментарии
Вопросы, находки и подсказки по этой странице.
Войди, чтобы задать вопрос или помочь другим.