Опционалы, или опциональные типы данных — это специальный механизм Swift, используемый в тех случаях, когда некоторое значение может существовать, а может и отсутствовать. Для работы со значением, хранящимся внутри опционала, его необходимо извлечь/развернуть (произвести unwrap).
Любой тип данных может стать базовым для опционала, т.е. опциональный тип может быть создан на основе совершенно любого типа данных.
Вариант 1. С помощью конструкции Optional<T>
var value: Optional = 5 var value = Optional(5)
Вариант 2. С помощью конструкции T?
var value = Int?(5)
где T — тип данных, на основе которого создается опционал.
Вариант 2 (T?) является синтаксическим сахаром, упрощающим работу с опционалами.
Вариант 1. Опциональное связывание с помощью конструкции if let
if let unwrapValue = optionalValue {
print(unwrapValue)
}
Вариант 2. Опциональное связывание с помощью конструкции guard let
guard let unwrapValue = optionalValue else {
return
}
Вариант 3. Принудительное извлечение (force unwrap)
optionalValue!
Вариант 4. Косвенное извлечение (implicitly unwrap)
var optionalValue: Int! = 5 // при обращении к a значение будет автоматически неявно извлекаться optionalValue // 5
Вариант 5. Объединение с nil (nil coalescing)
optionalValue ?? 5
Не лишним будет упомянуть о следующих вариантах доступа к опциональным значениям
Вариант 6. Опциональные цепочки
a?.someMethod()
Вариант 7. Извлечение c операторами as и try
optionalValue as! UInt try! optionalValue.someMethod()
В качестве пример можно рассмотреть некую функцию загрузки значения из базы данных. Она возвращает nil, если соответствующее значение не найдено в базе, и значение опционального типа – если найдено.
С точки зрения внутренней структуры Optional – это перечисление (enum), имеющий два возможных значения: none и some(T), где T – базовый для опционала тип данных. Данное перечисление подписано на протокол ExpressibleByNilLiteral, что позволяет ему в качестве значения иметь nil.
enum NewOptional: ExpressibleByNilLiteral {
case some(T)
case none
init(nilLiteral: ()) {
self = .none
}
init(_ some: T) {
self = .some(some)
}
}
let newOptionalValue = NewOptional(6)