Что это такое и как их можно использовать для защиты вашего кода от сбоев?
Прошел месяц с тех пор, как я начал изучать Swift. Если честно, мне было интересно изучать этот язык. Но когда мне пришлось применить то, что я узнал, это оказалось большим испытанием (К счастью, я люблю испытания!).
Если быть точным, у меня были ожесточенные битвы с Optionals Swift. Я считал Optionals своими злейшими врагами. Но после нескольких дней работы и исследований мы с Optionals наконец пришли к правильному взаимопониманию, и теперь мы лучшие друзья!
Следовательно, эта статья предназначена для тех людей, которые только начали изучать Swift и сталкиваются с трудностями при дружбе с Optionals Swift. Давай начнем!
Что такое варианты?
Необязательные параметры - это тип переменных в Swift, которые либо содержат значение, либо обладают сверхмощностью nil
. Другими словами, они могут содержать или не содержать значение. Необязательную переменную можно объявить в Swift следующим образом:
var superOptional: String? print(superOptional)
Здесь переменная superOptional
- это Optional
переменная типа String
. Это означает, что он может либо содержать в себе какую-то строку, либо иметь значение nil
. Прямо сейчас, поскольку мы не присвоили переменной никакого значения, текущее значение superOptional
печатается как nil
. Однако когда дело доходит до объявления необязательных переменных, дело обстоит иначе. Например, если мы сделаем что-то вроде этого:
var superVariable: String print(superVariable)
Затем, как только мы завершим написание приведенного ниже кода, IDE начнет кричать на нас, говоря Variable ‘superVariable’ used before being initialized
.
Это ясно указывает на то, что нам не нужно инициализировать переменную Optional
перед ее использованием (поскольку она автоматически инициализируется с помощью nil
), но мы должны инициализировать необязательную или обычную переменную перед ее использованием.
Теперь перейдем к инициализации нашей superOptional
переменной.
superOptional = "Hello world!" print(superOptional)
После добавления этого общий код будет выглядеть так:
var superOptional: String? // old code print(superOptional) superOptional = "Hello world!" // new code print(superOptional)
Результат будет примерно таким:
nil Optional(“Hello world!”)
Перед тем, как мы инициализировали нашу переменную superOptional
, ее значение было nil
. Однако после инициализации его строкой “Hello world!”
значение больше не было nil
, и поэтому на выходе получилось Optional(“Hello world!”)
.
Но подождите, результат должен был быть just“Hello world!”
! Да, именно об этом я подумал, когда создал свою первую Optional
переменную. Но поскольку переменная, в которой хранится “Hello world!”
, является переменной Optional
, она была заключена в Optional()
. Есть способы извлечь или развернуть это значение и использовать его. Что я опишу в этой статье.
Распаковка опций
Есть шесть способов развернуть фактические значения (значения, не заключенные в Optional()
) из Optional
переменных. Они есть:
- Распаковка
Optionals
с использованием условий if-else - Оператор объединения Nil
- Принудительное разворачивание
- Необязательная привязка (
if let
) guard let
- Необязательная цепочка
1. Распаковка необязательных элементов с использованием условий if-else
Это способ разворачивания опций, в котором мы используем условия if-else, чтобы проверить, содержит ли Optional
значение nil
или нет. Если Optional
не содержит значения nil
, мы разворачиваем его, в противном случае печатаем строку “Default value”
. Давайте реализуем это.
var superOptional: String? superOptional = "Hello world!" if superOptional != nil { print(superOptional) } else { print("Default value") }
Это может быть знакомый способ раскрыть ценность для многих людей. Однако в Swift есть лучшие и более короткие способы выполнения этой работы. Так что распаковывать таким способом не рекомендуется.
2. Оператор объединения Nil
Использование оператора объединения nil - еще один способ развернуть необязательные параметры. Это лучший и более короткий способ разворачивания, чем использование условий if-else (способ, упомянутый чуть выше в этом разделе статьи). Этот оператор помогает нам либо разворачивать Optional
, если он имеет фактическое значение, либо задавая значение по умолчанию, если Optional
равно nil
. Например:
var superOptional: String? print(superOptional ?? "Default value") // nil coalescing operator
В приведенном выше примере переменная superOptional
имеет значение nil
, поскольку она имеет Optional
характер, и ей не было присвоено никакого значения. Следовательно, когда он разворачивается с помощью оператора объединения nil, за которым следует строка “Default value”
, nil
печатается не, а “Default value”
. Однако этого не произойдет, если superOptional
содержит фактическое значение. Давайте посмотрим на это на следующем примере:
var superOptional: String? superOptional = "Hello world!" print(superOptional ?? "Default value")
В приведенном выше примере результат отличается, поскольку superOptional
инициализируется строкой “Hello world!”
перед ее разворачиванием. Следовательно, на экране печатается “Hello world!”
, а не “Default value”
.
3. Принудительное разворачивание
Принудительное разворачивание, как следует из названия, - это способ разворачивания значений из дополнительных параметров, при котором мы принудительно разворачиваем значение из переменной, не заботясь о том, имеет ли Optional
фактическое значение или значение nil
. Мы делаем это, добавляя восклицательный знак (!) После имени Optional
переменной. Это небезопасный способ разворачивания, поскольку он приводит к фатальной ошибке, если Optional
содержит значение nil
. Этот метод следует использовать только в тех случаях, когда мы полностью уверены, что Optional
не содержит значения nil
.
Давайте посмотрим на это в действии:
var superOptional: String? superOptional = “Hello world!” print(superOptional) // prints Optional("Hello world!") print(superOptional!) // prints Hello world!
В этом примере мы видим, что существует Optional
переменная с именем superOptional
, которая имеет тип String
. Ему присваивается строка “Hello world!”
, и она инициализируется. Когда мы печатаем переменную superOptional
, не разворачивая ее, печатается Optional(“Hello world!”)
. Но когда мы печатаем его, добавляя восклицательный знак в конце, печатается Hello world!
. Таким образом, на Optional
выполняется принудительное развертывание для получения фактического значения. Но что, если мы попытаемся принудительно развернуть и распечатать переменную superOptional
без ее инициализации? Или что, если мы попытаемся сделать это, когда значение переменной равно nil
? Посмотрим на код:
var superOptional: String? // or var superOptional: String? = nil print(superOptional!) // force unwrapping
Когда мы выполняем приведенный выше код, наш код дает сбой, и мы получаем следующую ошибку:
Fatal error: Unexpectedly found nil while unwrapping an Optional value
Здесь, поскольку мы использовали принудительное развертывание Optional
со значением nil
, код потерпел крах. Следовательно, необходимо иметь в виду, что если мы собираемся использовать принудительное развертывание, мы должны быть уверены, что Optional
никогда не будет иметь значение nil
.
4. Необязательная привязка (если разрешена)
Дополнительное связывание - безопасная альтернатива принудительному разворачиванию. Принудительное развертывание приводит к сбою нашего кода, если Optional
, который мы пытаемся развернуть, состоит из значения nil
. Но, используя необязательную привязку, мы можем предотвратить это. В этом методе мы переходим к разворачиванию Optional
только после того, как убедимся, что он содержит фактическое значение. Для этого мы используем if let
. Чтобы пролить свет на это, давайте посмотрим на этот пример:
var superOptional: String? superOptional = "Hello world!" if let superValue = superOptional { // optional binding print(superValue) }
Здесь мы проверили, является ли superOptional
nil
или нет. Если это не nil
, значение присваивается superValue
. Следовательно, становится безопасным использование superValue
, значение которого было получено от superOptional
.
5. охранник пусть
guard let
- хорошая альтернатива if let
для развертывания опций. Если guard let
получает nil
значение Optional
, которое мы пытаемся развернуть, он ожидает, что мы выйдем из функции, цикла или условия, в которых мы его использовали. Однако разница между if let
и guard let
в том, что мы все еще можем использовать наш развернутый необязательный параметр, даже после кода guard let
. Давайте посмотрим на это на примере:
func printName(personName: String?){ guard let name = personName else { print(“No name has been passed.”) return } print(“Your name is \(name).”) } printName(personName: “John Doe”) // outputs "Your name is John Doe." printName(personName: nil) // outputs "No name has been passed.
Здесь у нас есть функция printName(personName:)
. Он принимает необязательный String
, называемый personName
, и использует guard let
, чтобы проверить, является ли personName
nil
или нет, а затем распечатывает другие выходные данные. В строке с guard let
значение personName
присваивается name
. Если значение personName
оказывается равным nil
, немедленно выполняется блок else
, и управление выходит из функции. В текущем примере сначала печатается “No name has been passed”
, а выполнение функции останавливается. Однако, если personName
не содержит значения nil
, блок else
пропускается и печатается имя человека. В данном случае печатается “Your name is John Doe.”
.
Не забудьте включить оператор return
в блок else
элемента guard let
, поскольку мы хотим остановить выполнение функции, как только будет обнаружено nil
значение.
6. Дополнительная цепочка
Если нам нужно иметь дело с несколькими опциональными опциями одновременно, опциональная цепочка может быть полезным подходом. Предположим, что у нас есть контроллер представления с текстовым полем с именем emailField
и имеет тип UITextField?
. Допустим, мы также установили @IBOutlet
для emailField
, что позволяет нам программно устанавливать различные свойства emailField
. В этом примере мы рассмотрим его свойство text
. Итак, если мы хотим проверить, состоит ли emailField
из значения nil
или какого-то фактического значения, мы можем использовать как необязательную привязку, так и принудительное развертывание следующим образом:
Использование дополнительной привязки для получения текстового значения emailField:
if let email = emailField, let emailText = email.text { print("The email address is: \(emailText)") }
Использование принудительного развертывания для получения текстового значения emailField:
if emailField != nil && emailField!.text != nil { print("The email address is: \(emailField!.text)") }
Хотя эти подходы можно использовать для разворачивания, становится трудно иметь дело с опциями, когда количество компонентов пользовательского интерфейса увеличивается в контроллере представления. Он превратится в огромное количество условных выражений, скобок и отступов, затрудняющих читаемость кода. Таким образом, в таких условиях может пригодиться необязательная цепочка. Например:
emailField?.text = "[email protected]"
Здесь переменная emailField
- это Optional
, за которой следует вопросительный знак. На этом этапе в нашем коде могут произойти две вещи: либо переменная emailField
не содержит nil
значение и доступ к свойству text
становится успешным, либо переменная emailField
содержит значение nil
и доступ к свойству text
завершается неудачно.
Когда доступ к свойству text
не удается, выполнение этой строки безопасно останавливается без сбоя кода. В данном примере свойство text
для emailField
не установлено в “[email protected]”
, когда emailField
равно nil
.
Другой пример, показывающий использование необязательной цепочки:
car?.wheel?.airPercent = 50
Вот и все, ребята! Я надеюсь, что эта статья дала вам несколько идей о том, как подружиться со Swift Optionals и использовать их. Я знаю, что вначале они выглядели как наши злейшие враги, но со временем вы поймете, насколько они полезны.
Удачного свифтинга!