Optionals в Swift нужны, чтобы отсутствие значения было видно в типе. Переменная либо содержит значение, либо содержит nil, и Swift заставляет вас обработать этот факт до использования. В этом уроке разберем String?, if let, guard let, optional chaining и опасный force unwrap через !
К концу урока вы напишете функцию, которая безопасно делает подпись пользователя и не падает, если имени нет
- Что получится в конце
- Что такое optional
- if let
- guard let
- Optional chaining
- Почему ! опасен
- Домашка: безопасный промокод
- Mini-check для optionals
- Частые ошибки и порядок проверки
- Как выбирать между if let, guard let и ??
- Практика: форма пользователя
- Почему Int("32") возвращает Optional
- Мини-правило для ревью своего кода
- Optional chaining на реальном примере
- Что может быть еще интересно по этой теме
- Что почитать дальше по Swift
Что получится в конце
Пример:
func userLabel(name: String?) -> String {
guard let name, !name.trimmingCharacters(in: .whitespaces).isEmpty else {
return "User: Guest"
}
return "User: \(name)"
}
print(userLabel(name: "Dinar"))
print(userLabel(name: nil))
print(userLabel(name: " "))
Ожидаемый вывод:
User: Dinar
User: Guest
User: Guest
Здесь name может отсутствовать, но программа не падает и возвращает понятный запасной вариант
Что такое optional
Обычная строка:
let name: String = "Swift"
не может быть nil
Optional-строка:
let name: String? = nil
может содержать строку или nil. Вопросительный знак меняет тип. String и String? — разные вещи
Если попытаться сразу взять:
name.count
компилятор остановит код. Он не знает, есть ли внутри строка. Сначала нужно безопасно извлечь значение
if let
if let достает значение, если оно есть:
let nickname: String? = "Dinar"
if let nickname {
print("Nickname: \(nickname)")
} else {
print("No nickname")
}
Внутри блока if nickname уже обычный String, а не String?
Этот способ хорош, когда у вас есть два нормальных сценария: значение есть и значения нет
guard let
guard let удобен, когда без значения функция не может продолжать работу:
func printName(_ name: String?) {
guard let name else {
print("No name")
return
}
print(name)
}
После guard переменная доступна ниже как non-optional. Код получается ровнее: плохой сценарий выходит раньше, основной путь остается без лишней вложенности
В реальных функциях guard часто используют для проверки входных данных, URL, id, токенов и обязательных зависимостей
Optional chaining
Optional chaining позволяет вызвать свойство или метод только если значение есть:
let length = name?.count
Если name содержит строку, length будет optional-числом с длиной. Если name == nil, length будет nil
Для запасного значения используйте nil-coalescing:
let length = name?.count ?? 0
Теперь length — обычный Int, потому что на случай nil есть 0
Почему ! опасен
name!.count
говорит Swift: «я уверен, что здесь не nil». Если вы ошиблись, приложение упадет
Иногда ! встречается в шаблонах, legacy-коде или местах, где значение действительно гарантировано внешней системой. Но для новичка правило жесткое: не ставьте !, чтобы просто заткнуть компилятор
Перед ! проверьте:
- Можно ли использовать
if let - Можно ли использовать
guard let - Можно ли дать fallback через
?? - Можно ли изменить тип, чтобы значение не было optional
Если да, force unwrap не нужен
Домашка: безопасный промокод
Создайте функцию:
func promoLabel(code: String?) -> String
Правила:
- если
code == nil, вернуть"No promo" - если строка пустая после trimming, вернуть
"No promo" - иначе вернуть
"Promo: CODE"
Проверьте:
print(promoLabel(code: nil))
print(promoLabel(code: ""))
print(promoLabel(code: " SAVE10 "))
Дополнительная задача: сделайте код uppercase перед выводом
Mini-check для optionals
Когда видите String?, задайте три вопроса:
- где значение может стать
nil - кто обязан обработать отсутствие
- есть ли рядом подозрительный
!
Если optional передается через много функций без обработки, код становится мутным. Лучше обработать отсутствие там, где понятно бизнес-решение: показать гостя, вернуть ошибку, остановить функцию или дать fallback
Частые ошибки и порядок проверки
Путаете String и String? Это разные типы. Optional нужно извлекать перед обычным использованием
Ставите ! без причины Force unwrap может уронить приложение. Используйте его только там, где гарантия действительно железная
Даете неверный fallback ?? "" не всегда хорош. Пустая строка может скрыть ошибку данных
Делаете слишком глубокие if let Если вложенность растет, попробуйте guard let для раннего выхода
Как выбирать между if let, guard let и ??
У optionals есть несколько рабочих приемов, и новичок часто пытается выбрать один “самый правильный”. На практике выбор зависит от формы кода
Используйте if let, когда значение нужно только внутри небольшой ветки:
let email: String? = "dinar@example.com"
if let email {
print("Send email to \(email)")
} else {
print("Email is missing")
}
Используйте guard let, когда без значения функция не может нормально продолжаться:
func showProfile(name: String?) {
guard let name else {
print("Name is missing")
return
}
print("Profile: \(name)")
}
Используйте ??, когда нужен короткий запасной вариант:
let city: String? = nil
print(city ?? "City not set")
И почти никогда не начинайте с !. Force unwrap уместен только когда вы действительно доказали, что nil невозможен, а не просто хотите быстрее убрать ошибку компилятора
Практика: форма пользователя
Представьте, что пользователь заполняет профиль. Имя обязательно, никнейм может отсутствовать, возраст приходит строкой из поля ввода:
let rawName: String? = "Dinar"
let nickname: String? = nil
let rawAge: String? = "32"
guard let name = rawName else {
fatalError("Name is required")
}
let displayName = nickname ?? name
let age = Int(rawAge ?? "")
print("Display name: \(displayName)")
if let age {
print("Age: \(age)")
} else {
print("Age is not valid")
}
Здесь есть сразу три типичных ситуации: обязательное значение через guard, запасной вариант через ?? и преобразование строки в число, которое тоже возвращает optional
Поменяйте rawAge на "thirty" и запустите код. Программа не должна падать. Она должна попасть в ветку Age is not valid
Почему Int("32") возвращает Optional
На первый взгляд странно: почему преобразование строки в число не возвращает обычный Int. Ответ простой: не каждая строка является числом
let first = Int("32")
let second = Int("Swift")
first будет Optional(32), а second будет nil. Swift не может молча превратить слово Swift в число, поэтому честно показывает в типе: результат может отсутствовать
Именно поэтому optionals так важны в реальном коде. Данные приходят из форм, URL, JSON, словарей, настроек и пользовательского ввода. Там отсутствие значения — нормальная часть жизни программы
Мини-правило для ревью своего кода
Перед тем как оставить !, задайте себе три вопроса:
- Кто гарантирует, что здесь не будет
nil - Что увидит пользователь, если гарантия нарушится
- Можно ли заменить
!наif let,guard letили??
Если на первый вопрос нет четкого ответа, force unwrap лучше убрать. Это не делает код длиннее “ради красоты”, это делает отказ программы управляемым
Optional chaining на реальном примере
Optional chaining помогает аккуратно пройти по цепочке, где любое звено может отсутствовать:
struct Profile {
let email: String?
}
struct User {
let profile: Profile?
}
let user = User(profile: Profile(email: "dinar@example.com"))
let emailLength = user.profile?.email?.count
print(emailLength ?? 0)
Если profile или email будет nil, выражение не упадет. Оно вернет optional-результат, который можно обработать через ?? или if let
Этот прием часто встречается при работе с вложенными данными из API. Но если цепочка становится слишком длинной, лучше остановиться и вынести проверку в отдельные понятные шаги
Что может быть еще интересно по этой теме
Optionals похожи на null safety в Kotlin? Да по идее: отсутствие значения видно в типе. Но синтаксис и привычные idioms отличаются
Почему Swift вообще допускает nil? Потому что отсутствие значения реально бывает: пользователь не ввел поле, URL не собрался, словарь не нашел ключ. Swift заставляет обработать это явно
Когда использовать guard let? Когда без значения дальше нет смысла продолжать. Это делает основной путь функции прямым
Что дальше после optionals? Функции, struct и class. Там optional-поля и безопасное извлечение будут встречаться постоянно
Что почитать дальше по Swift
- Swift с нуля: первая программа в Playground
- Функции, struct и class в Swift
- Массивы, словари и циклы в Swift
- SwiftUI: первый экран с Text, Button и @State



