Константы и переменные любого типа данных в языке программирования Swift (строкового, целочисленного, числового с плавающей точкой, логического и так далее) всегда имеют некое непустое значение. Это относится также к переменным, хранящим ссылки на объекты классов: даже в этом случае переменная не может содержать никакой ссылки, она всегда указывает на какой-либо объект. (Это очень принципиальное отличие, например, от языка программирования C#, где все ссылочные переменные могут быть пустыми, то есть равными nil.)
Однако в процессе написания программы часто возникает необходимость указать для переменной именно отсутствие какого-либо значения вовсе. Для этого при программировании в Swift существуют опционалы.
Опционал (другими словами, опциональный тип данных) предоставляет собой определение переменной, реализующее следующие две возможности: переменная-опционал может содержать значение некоего определенного типа данных, называемого в дальнейшем базовым, либо не содержать ничего вообще. Для того чтобы показать отсутствие значение у переменной-опционала, нужно присвоить ей особое значение nil.
Итак, в общем виде определяется опционал следующим образом:Optional<Type>
(полный вариант записи опционала) или Type!
(краткий вариант записи), где Type — базовый тип.
Например:var x: Optional<Int>
var y: Int?
Оба варианта записи означают, что переменные x и y могут содержать целое число или не содержать ничего (быть равными nil). Также следует отметить, что оба варианта записи создадут переменные одинакового типа (то есть в дальнейшем запись x = y не вызовет ошибки несоответствия типов данных).
(Проводя дальнейшее сравнение с программированием в C#, опционал в Swift — это, по сути, обычный ссылочный тип данных в C#. Например, String? языка Swift аналогичен обычному String в C#).
Важно: при программировании на Swift при объявления переменной-опционала необходимо явно указать ее опциональный тип:
var s: String? = «строка-опционал»
(В случае записи var s = «строка»
будет создана переменная обычного типа String. В случае записи var s = nil
компилятором будет выдана ошибка «‘nil’ requires a contextual type»
— nil требует контекстного типа).
При работе с опционалами нельзя выполнять операции непосредственно между переменными опционального и базового типа. Это приведет к ошибке во время компиляции. Пример:
var x1: Int = 111
var x2: Int? = 222
Выполнение выражения x1 + x2 вызовет ошибку «Value of optional type Int? must be unwrapped to value Int»
(значение опционала должно быть распаковано). Иными словами, значение переменной-опционала должно быть неким образом преобразовано к базовому типу.
При программировании на Swift существует несколько таких механизмов преобразования опционала к базовому типу:
• force unwrapping;
• implicity unwrapping;
• optional bunding;
• nil coalescing.
Механизм force unwrapping
Механизм force unwrapping (принудительная распаковка) явно преобразует опционал в значение базового типа путем добавления восклицательного знака после имени переменной-опционала.
Например:var x1: Int = 10
var x2: Int? = 20
var x3 = x1 + x2!
При таком способе получения значения опционала, содержащее nil, возникает ошибка во время выполнения программы.
var i: Int? = nil
Выполнение выражения i!
приведет к ошибке при выполнении программы «Unexpectedly found nil while unwrapping an optional value»
(Неожиданное обнаружение nil во время распаковки значения опционала).
При использовании механизма force unwrapping
для получения значения переменной-опционала необходимо быть уверенным, что опционал имеет непустое значение. Для выполнения такой проверки используется условный оператор и операторы сравнения опционала с nil (равенства «==»
и неравенства «!=»
).
Например:let x1: Int = 333
let x2: Int? = 444
if x2 != nil {let x3 = x1 + x2!}
Механизм implicity unwrapping
Другим вариантом извлечения значения переменной-опционала является механизм implicity unwrapping (неявного извлечения).
Суть его заключается в следующем. В некоторых случаях структура разрабатываемой вами программы может быть такова, что опционал всегда будет иметь некое непустое значение после того, как это значение было впервые установлено. В этом случае будет удобным избежать необходимость проверки и извлечения значения всякий раз, когда требуется получить значение.
Именно в таких случаях используется механизм implicity unwrapping
. Для этого при инициализации опционала знак вопроса (?) заменяется на знак восклицания (!).
let str1: String! = «implicity unwrapping»
let str2: String? = «optional string»
let str3: String! = str2! // другой вариант неявной распаковки опционала
Механизм optional binding
Механизм optinal binding (связывание опционала) используется для определения наличия в опционала непустого значения и, в случае если это так, получения значение опционала во временную переменную или константу.
В общем виде механизм optional binding выглядит следующим образом:if let временная переменная = опционал { //действия для непустого опционала }
else { // действия для пустого опционала}
В случае, если опционал содержит непустое значение, создается временная переменная (или константа), в которую будет записано распакованное значение опционала, и выполнены действия тела условного оператора (значение опционала доступно через созданную временную переменную (константу), имеющую базовый тип; также необходимо отметить, что, учитывая правила определения области видимости переменных и констант в Swift, временная переменная будет доступна только в блоке действия для непустого опционала
).
В противном случае, когда значение опционала не может быть извлечен (равен nil) — выполняется блок else. Блок else может отсутствовать.
var x1: Int = 100
var x2: Int? = 200
if let x_temp = x2 { let x3 = x1 + x_temp }
Механизм nil coalescing
Еще одним вариантом распаковки опционала является механизм nil coalescing (соединения с nil) с использованием оператора ??
.
В общим виде такой способ выглядит следующим образом:let переменная = опционал ?? значениепоумолчанию
В случае, когда опционал не равен nil, его значение записывается в переменную, в противном случае в переменную записывается значение по умолчанию, расположенное справа от оператора ??
.
В примере приведенный механизм реализуется следующим образом:let x1: Int = 1
let x2: Int? = 2
let temp = x2 ?? 0
let x3 = x1 + temp
Наиболее безопасными и поэтому рекомендуемыми механизмами работы с опционалами являются optional binding
и nil coalescing
.
Если вам интересно развитие в сфере разработки iOS-приложений, предлагаем ознакомиться с курсами iOS-разработки: базовый уровень, продвинутый уровень.