Forced unwrapping swift что это
Перейти к содержимому

Forced unwrapping swift что это

  • автор:

Forced unwrapping swift что это

Опциональные типы представляют объекты, которые могут иметь, а могут и не иметь значение. Опциональные типы выступают двойниками базовых типов. Все они имеют в конце вопросительный знак: Int? , String? и т.д. Вопросительный знак как раз указывает, что это опциональный тип.

Например, рассмотрим следующую ситуацию:

let someString = "123" let someNumber = Int(someString)

Здесь инициализатор Int(someString) преобразует строку someString в число. В данном случае у нас все нормально, так как строка «123» действительно содержит число 123. Однако, что, если бы переменная someString представляла бы строку «hello»? В этом случае инициализатор не смог бы преобразовать строку в число. Поэтому инициализатор возвращает не просто объект Int, а Int? , то есть объект, который может иметь, а может не иметь значения.

По факту, если объект не имеет значения, то ему присваивается специальное значение nil . В коде мы также можем установить явным образом это значение:

var number: Int? = 12 number = nil // теперь переменная number не имеет значения

Значение nil может применяться только к объектам опциональных типов.

Фактически запись типа Int? является сокращением от Optional . То есть мы также можем определить переменную следующим образом:

var number: Optional = 12

Несмотря на то, что в примере выше переменной number присваивается число 12, но фактически переменная будет иметь в качестве значения Optional(12) , то есть мы могли бы написать следующим образом:

var number : Optional= Optional(12) // или так var number2 = Optional(12)

При этом опять же стоит понимать, что Optional , это не то же самое, что и Optional или Optional
var number = Optional(12) number = Optional(«12») // Ошибка number представляет тип Optional, а не Optional

Получение значения из Optional

При работе с объектами опциональных типов следует помнить, что они не эквивалентны объектам обычных типов. То есть следующий пример у нас работать не будет:

var a: Int? = 12 var b: Int = 10 var c = a + b // ошибка - разные типы

a и b здесь переменные разных типов, хотя казалось бы обе переменных хранят целые числа. И чтобы полноценно работать с объектами опциональных типов, следует извлечь из них значение. Для извлечения значения используется оператор ! — восклицательный знак после названия объекта опционального типа. Данный оператор еще называют unwrap operator или forced unwrap operator :

var a: Int? = 12 var b: Int = 10 var c = a! + b // с = 22
var b: Int = 10 var a: Int? = Int("123") b = a! + b print(a!) // 123 print(b) // 133

Неявное получение значений Optional

Swift предоставляет еще один способ получения значения подобных типов, который заключается в использовании типов Optional с неявно получаемым значением (implicitly unwrapped Optional):

var b: Int = 10 var a: Int! = Int("123") b = a + b print(a) // 123 print(b) // 133

Здесь переменная a имеет тип Int! , а не Int? . Фактиччески это тот же самый Optional, но теперь нам явным образом не надо применять оператор ! для получения его значения.

Проверка Optional на nil

В то же время если переменная a в примере выше не будет содержать конкретное значение, то программа опять же выбросит ошибку. Например? в случае var a: Int! = Int(«abc») или var a: Int? = Int(«abc») . Поэтому перед использованием объектов опциональных типов желательно проверить, что они имеют какие-либо значение.

Для проверки мы можем использовать условную конструкцию if. Ее общая форма:

if var переменная | let константа = опциональное_значение < действия1 >else

Если опциональное_значение не равно nil, то оно присваивается создаваемой переменной (или константе), и выполняются действия1. Иначе выполняются действия2.

var str: String = «123» var b: Int = 10 if var a = Int(str) < a+=b print(a) >else

Если выражение Int(str) (которое возвращает объект Int?) успешно преобразует строку в число, то есть будет иметь значение, то создается переменная a, которой присваивается полученное значение, и затем выполняется код:

a+=b print(a)

Если же преобразование из строки в число завершится с ошибкой, и выражение Int(str) возвратит значение nil , то выполняется код в блоке else:

else

Но также в данном случае мы могли и по другому проверить на значение nil:

var str: String = «123» var b: Int = 10 var a: Int? = Int(str) if a != nil < a+=b print(a) >else

Если надо проверить значения нескольких переменных или констант, то все их можно указать в одном выражении if:

let a = Int(«123») let b = Int(«456») if let aVal = a, let bVal = b < print(aVal) print(bVal) >else

В данном случае выражение if выполняется, если и a, и b не равны nil. Иначе выполняется блок else.

Сравнение объектов Optional

При сравнении объекта Optional с объектом конкретного типа, Swift преобразует объект конкретного типа к типу Optional:

let a: Int? = 10 if a == 10 < print("a is equal to 10") >else

И таким образом работают операции == и !=. Однако с операциями , = все будет несколько иначе. Например, следующий код выдаст ошибку:

let a: Int? = 10 if a > 5

И в подобных операциях к объекту Optional необходимо применить оператор !:

let a: Int? = 10 if a != nil && a! > 5

Optional в switch..case

Если сравниваемое значение в конструкции switch представляет объект Optional, то с помощью операции ? мы можем получить и сравнивать его значение при его наличии:

let i = Int(«1») switch i

Оператор nil-объединения

Оператор ?? позволяет проверить значения объекта Optional на nil. Этот оператор принимает два операнда a ?? 10 . Если первый операнд не равен nil, то возвращается значение первого операнда. Если первый операнд равен nil, то возвращается второй операнд:

let a = Int("234") let b = a ?? 10 print(b) // 234

В данном случае поскольку константа a не равна nil, то выражение a ?? 10 возвращает значение этой константы, то есть число 234.

как сделать правильно анрап в swift

Чтобы избавиться от optional, вам надо делать force unwrap посредством добавления ‘!’. Помните, что ваше приложение скрешится, если наткнется на nil, то есть если вы вызовете firstName! в момент, когда firstName == nil , то это креш.

self.firstName = firstName! 

При этом, я бы сказал, что такое решение неправильное, а правильно будет избавиться от ‘?’ в объявлении переменных инстанса, поскольку вы их все присваиваете в ините.

Три ошибки iOS-разработчика, которые могут дорого стоить

Создание iOS-приложения – непростая задача. Разработчикам хочется как можно быстрее завершить этот процесс и наконец запуститься в AppStore. Но на этом все не заканчивается: впереди у создателей долгие годы исправления ошибок, улучшения функций и совместной работы с другими разработчиками. Мы бы хотели немного облегчить им жизнь и для этого решили разобрать три вещи, которые нужно избегать при iOS-разработке (спасибо Envato Tuts+ за информацию).

1. Константы, константы… мне и с переменными норм

На первый взгляд, переменные более универсальны чем константы. Но если вы можете использовать константу, то лучше к переменным не прибегать. У констант есть несколько преимуществ.

Читаемость

Это, пожалуй, главное преимущество. Предположим, вы пишете e-commerce приложение для США. Указываете локальную ставку налога с продаж — 8,75%. И в этот момент к разработке подключается условный Вася, который о налоге с продаж ничего не знает.

Если вы введете переменную для обозначения ставки налога с продаж, он может изменить ее буквально одной строкой кода, что может серьезно навредить приложению. Если вы поменяете ключевое слово с var на let , компилятор сообщит, что это значение не может быть изменено, и Вася отдернет свои судьбоносные персты от клавиатуры.

Ссылка на значение

С помощью let можно ссылаться на какое-либо значение в коде. Создаете вы приложение, создаете и вдруг по примеру Rolling Stones решаете покрасить все в черный. Если вы прописали константу, то при изменении в одном месте все остальные ссылки на цвет тоже изменятся. А если нет, то придется выискивать и менять все вручную.

Инстанцирование класса или структуры

Если вы создаете синглтон (singleton), вам нужно при этом создать и общий экземпляр (shared instance) класса. Обычно это делается через объявление static let внутри объявления класса. После этого вы даете имя константе, присваиваете ее экземпляру класса и можете спокойно использовать его во всем приложении.

Если вам нужно создать экземпляр обычного класса (скажем, в ViewController.swift), вы создаете константу и присваиваете ее экземпляру нужного вам класса – таким образом возникает ссылка, которой вы можете легко воспользоваться во всем файле. Константы снова в деле!

Как видите, константы имеют много преимуществ. Они повышают читаемость кода, они полезны для хранения неизменяемых величин и, конечно, не так бесполезны, как вы думаете. Крутые разработчики любят константы и изменяют им с переменными только если от изменения значений никуда не деться.

2. Bang Operator! Как круто звучит, то что надо для опционала!

Опционалы — очень мощная фича Swift. Это типы а-ля int и String , аннотированные с вопросительным знаком после объявления типа. Если вы хотите объявить переменную как опциональную строку, то можете просто написать:

var someVariable: String?

Это сигнал компилятору, что в ней либо будет значение, либо не будет. String? и String считаются двумя разными типами.

Опционал — это подарочная коробка. В этой коробке может храниться, а может и не храниться значение. Если вы хотите это узнать, нужно опционал развернуть. Это делается по-разному.

Неправильно: Forced Unwrapping (Принудительное извлечение значения)

Эта операция (выполняется с помощью восклицательного знака) называется Bang Operator. Не советуем ей пользоваться. Если в значении извлекаемого таким образом опционала будет nil (ничто), то приложение рухнет. Вот например как здесь:

var someVariable: String? var somethingElse: String = "hello" func setupApp()

В этом примере приложение упадет, потому что мы не определили значение someVariable и пытаемся присвоить его переменной типа String. Как раз для защиты от таких ошибок и создавались опционалы, а мы сводим все их усилия не нет.

Правильно: Optional Binding (Привязка опционала)

Это один из самых популярных методов работы с опционалами. Вы просто присваиваете значение опционала константе через инструкцию if. Если из опционала можно извлечь значение, компилятор входит в замыкание, и вы можете использовать созданную константу. В противном случае вы попадаете на ветку else и делаете вид, что ничего не произошло.

Для сравнения возьмем тот же пример:

var someVariable: String? var somethingElse: String = "hello" func setupApp() < if let theThing = someVariable < self.somethingElse = self.someVariable! >else < print("error") >> 

С привязкой опционала компилятор не рушит все приложение, а спокойно входит в ветку else и печатает «ошибку».

И снова правильно: Optional Chaining (опциональная цепочка)

Другим распространенным способом безопасного извлечения опционалов является опциональная цепочка. Так вы сможете полностью избежать значений nil с помощью всего одной строки. Если в какой-то момент такое значение будет получаться, эта строка кода просто перестает выполняться. Например:

var someClass: SomeClass? = SomeClass() var somethingElse: String? func setupApp()

Если someClass равен nil, то не будет выполнена вся строка, значение somethingElse становится равным nil. Если значение отлично от nil, как в примере выше, то оно присваивается переменной somethingElse. В любом случае приложение не упадет.

И опять верно: Nil Coalescing (Оператор объединения по nil)

Этот метод позволяет обрабатывать опционалы одной строкой, но в отличие от метода выше, вы обязаны указываете значение по умолчанию или «else». То есть для сценария, когда опционал окажется равным nil). Например:

var someVariable: String? var somethingElse: String = "hello" func setupApp()

Выглядит загадочно, но суть проста. Если выражение слева имеет какое-либо значение (то есть не равное nil), то это значение и будет использовано. Если значение равно nil, то будет использовано значение по умолчанию – в этом случае, захардкоженная строка. Выражение справа должна быть отлично от nil, а его тип должен быть неопциональным — иначе теряется весь смысл.

3. Оставим все эти шаблоны архитектуры на потом

И напоследок классическая ошибка. Многие не структурируют код, отчего страдает устойчивость, эффективность и способность его поддерживать в принципе. Можно втиснуть весь свой код в классы ViewController, но этот опрометчивый шаг отольется горючими слезами, когда придется изменить и дебажить код.

Код — это фундамент, на котором вы разрабатываете свое приложение. Без последовательно заложенного фундамента многоэтажный дом вашего приложения легко обрушится. Фундамент iOS приложения – это выбранный шаблон проектирования. Рассмотрим два наиболее часто используемых шаблона.

MVC (Model-View-Controller)

Шаблон проектирования Model-View-Controller, или MVC, разделяет каждую часть вашего кода на три части: модель, вид и контроллер.

  • Модель. Это по сути данные приложения. Эта часть охватывает многократно используемые структуры и классы, которые работают только с данными приложения. Модель не работает ни с чем, что связано с view или с тем, как информация будет показана пользователю.
  • Вид. Отвечает только за визуальное представление данных, а также за взаимодействие с пользователем. Он не обрабатывает ничего, что связано с данными или с конкретными view. Это просто класс, который можно многократно использовать без повторения кода.
  • Контроллер. Вот наш главный герой. Он берет данные из модели, а затем отправляет их во view, чтобы отобразить их для пользователя. Обычно это происходит в ViewController.swift – он воспринимает входные данные и меняет модель по мере необходимости.

Синглтоны

Синглтон — это единственный экземпляр класса, который всегда присутствует в памяти. И что в нем особенного? Предположим, вы создаете приложение, которое подключается к базе данных, и вам нужно куда-то разместить все подключения. Синглтоны для этого подойдут идеально. Вот как их создавать:

// Declaration class DataService < static var shared = DataService() func createUser() < >> // Call-site DataService.shared.createUser() 

Если следовать этим простым советам, приложение будет легче поддерживать, и вы найдете ошибки быстрее клиентов.

Все рассмотренные нами ошибки прекрасно иллюстрируют старинную русскую мудрость: «Тише едешь — дальше будешь». Надеемся, что статья была полезна, и ждем, что вы тоже расскажете нам, как обходили какие-нибудь подводные камни iOS-разработки. Обещаем приятный подарок от Программы ЕФС автору самого оригинального рассказа!

  • Блог компании Сбер
  • Разработка под iOS
  • Swift

Опциональные типы данных в языке Swift

Я новичок, выбрал для себя язык программирования Swift и сейчас его изучаю. Проштудировал недавно раздел «Опциональные типы данных» в учебнике. Решил систематизировать его в таком своеобразном конспекте. Подобный подход, как известно, помогает лучше понять и запомнить. А ещё, возможно, эти заметки пригодятся другим пользователям GeekBrains. Итак, начнём.

Кстати, если вы только начинаете изучать Swift, стоит пройти бесплатный интенсив по разработке на Swift от GeekBrains.

Повторяем, что такое типы данных

Что такое типы данных, о которых мы так часто говорим? Посмотрим на примерах. Предположим, есть переменная «a» и у неё есть значение «12». И это тип данных «Int». Кроме «Int» мы знаем ещё такие типы данных: «Double», «Float», «Bool» и др.

И далее, под типом данных можно понимать почти всё, что есть в программировании. Например, «переменная» или «константа» могут рассматриваться как определённые типы данных. «Объект», «класс», «структура» — это тоже определённые типы данных. Для простоты изложения и понимания дальше будет говориться в основном о простых, так называемых примитивных типах, в основном об «Int». Тогда многие примеры будут более понятны.

Что такое опция?

Слово «опция» трактуется словарём как «факультативная возможность». На самом деле это определение не объясняет, а ещё больше усложняет, поскольку появляется ещё одно, хоть и знакомое, но не очень понятное слово «факультативный». Смотрим словарь — необязательный, дополнительный. Теперь, если сложить всё вместе, получается такое определение «опции» — необязательная, дополнительная возможность.

В свою очередь, при работе с компьютером слова «Option», «Optional», «Опционально» довольно часто встречаются на сайтах при регистрации аккаунтов, заполнении различных анкет. Это означает, что соответствующий пункт можно заполнять, а можно и не заполнять. Соответственно, содержание там может быть, а может и не быть.

Опциональный тип данных

В программировании, в частности в Swift, тоже довольно часто встречаются такие слова, как «optional», «optionals», «опционал», «опционалы» и т. д. Ими обозначают опциональный тип данных. Это такой тип данных, в котором значение может быть, а может и не быть.

Откуда ноги растут

Ноги растут из математики, из понимания смысла цифры «0». Ноль, нуль от лат. nullus — никакой. Слово «ноль» чаще используется в повседневной речи, а слово «нуль» прижилось в математике. Например, «нулевое значение» (никто ведь не говорит «нолевое значение»).

Цифре «0» древние индийские математики приписывали магические значения: это не просто цифра, это отсутствие цифр, это таинственная пустота, которая ничего не значит и в то же время влияет на все остальные цифры. Сравните, цифра «1» сама по себе и цифра «100», где единица с двумя нулями. Это уже совсем другая цифра. Схематически отношение между «0» и остальными цифрами можно представить так:

Нуль в программировании

В программировании придумали, что «0» это тоже значение, нулевое. Точнее, это придумали и раньше в математике, а программисты это используют для решения своих задач.

Ноль это тоже значение, мы же его используем в расчётах. У нас ведь 10 цифр, а не 9, значит 0 имеет смысл, имеет какое-то своё значение. Как уже было показано выше, 1 без 0 — одно значение. А вместо с нулем или нулями, например, 100 — уже совсем другое значение. И т.д.

Посмотрим на примеры, более тесно связанные с программированием. Например, в коммерческой деятельности, когда программа учитывает продажи. Например, в один день не было продаж. Можно сказать, что продаж было «0». Или, например, было продано на 5 тыс. руб., и в то же время кто-то вернул товар тоже на 5 тыс. руб. — итоговый результат тоже получается «0».

Но по смыслу, по своему содержанию, «0» в первом случае отличается от «0» во втором. Т.е. в первом случае «0» — это отсутствие значения, а во втором — это результат определённых операций, именно нулевое значение.

Ещё один пример — отрицательные числа (см. рисунок). Здесь более наглядно видно, что «0» на данной шкале — это уже не отсутствие значения, а определённое нулевое значение.

Заодно предыдущую картинку тоже можно модифицировать в такую:

Таким образом, в программировании «0» считают таким же значением как и другие цифры, просто оно называется нулевым. А вот для отсутствующего значения придумали ещё одно название — nil или «пустота».

Резюмируем для закрепления: nil — это отсутствие значения, а «0» — это уже наличие значения, нулевое значение.

Что это нам даёт? Мы можем переменной присвоить значение «0» и использовать её также, как и другие переменные. Или мы можем создать переменную и присвоить ей значение nil. И вот тогда мы понимаем, что это особая переменная, у неё нет значения, «пустота», с ней надо вести себя осторожно, не так, как с другими переменными. Во всяком случае мы её обозначили, промаркировали и теперь можем её каким-то образом обрабатывать. А пока этого не делали, она была просто неуправляемой.

Пример ситуации, где может быть опциональный тип данных

Например, мы делаем запрос к сайту интернет-магазина: сегодня среда? Сервер может ответить: да или нет, true или false. Но если в этот момент разорвалось соединение и сервер не ответил, программа получит ноль и преобразует его в false. Мы получим ответ, что сегодня не среда, хотя на самом деле может быть как раз и среда.

Особенности обработки nil в Swift

Мне не очень нравится, когда в учебниках для начинающих сравнивают языки программирования. Там и так сложно разобраться, а тут на тебя наваливают ещё больше. Но сейчас такой случай, что без этого не обойтись. И это полезно как раз для начинающих.

Итак, в Objective C если от сервера в вышеназванном примере не поступает информация, то программа классифицирует его как false и выдаёт результат, что сегодня не среда. И если к результату ответа привязано какое-то действие, то может произойти ошибка, а то и падение системы. Почему это происходит? Потому что булевые значения строятся по типу: если это не true, значит это false. Если не пришёл ответ true, то всё остальное автоматом относится к false.

В Swift появился третий тип ответа — отсутствие ответа: к true и false добавлен nil — пустое значение, отсутствие значения. Тогда программа действует методом исключения уже в три этапа: если это не true, то это может быть nil или false; если это не nil, значит это false.

Как часто это встречается или насколько это важно

Опытные разработчики говорят, что встречается такая ситуация часто и что это одна из важных тем в языке Swift и в программировании в целом.

Какие типы данных могут быть опциональными?

В Swift в качестве nil всегда будет определённый тип данных (например, объект, класс, число, Int, Double, структура, точка). В Objective C только объект может быть nil. В Objective C nil — это чёрная дыра; если мы посылаем запрос к объекту, который nil, то обратно получаем либо nil, либо 0.

В Swift послать к nil что-нибудь невозможно, программа упадёт. В Swift объявить опциональным типом данных мы можем только конкретный тип. Если мы объявили переменную с опциональным типом Int, то в ней уже не может быть других типов данных (ни Double, ни String и пр.). Точно также, если мы объявили опциональный Double, то в этой переменной уже не может быть Int.

Синтаксис опционального типа данных

Опциональным является не переменная и не её значение; опциональным является тип данных. Это не так важно знать наизусть в начале обучения, но иногда помогает не запутаться в терминах. Чтобы обозначить, что переменная обладает опциональным типом данных, к обозначению этого типа добавляется вопросительный знак. Пример:

Мы объявляем переменную по имени «optSample», задаём тип данных Int и указываем, что это не обычный Int, а опциональный (- Int?). Это означает, что в некоторых случаях у данной переменной может не быть значения. И в песочнице Swift покажет это значение уже с дополнительным маркером: Some 12. Т. е. не просто 12, а некоторое значение 12.

Как определить, когда использовать опциональный тип данных

В каких случаях может не быть значений и нужно использовать опциональный тип данных? Это программисты определяют сами. На основе какого-то своего опыта, предварительной оценки ситуации. Это своеобразная подсказка из опыта старших товарищей: в некоторых случаях данные могут отсутствовать. И если не подстраховаться, то программа может неправильно работать (как в случае со средой выше) или вообще упасть.

Поэтому, если мы уверены, что такой ситуации не будет и данные будут всегда, тогда смело ставим обычный Int или другой тип данных. Но если мы знаем или даже просто предполагаем, что значений может не быть, тогда стоит поставить именно опциональный тип данных.

Как использовать опциональный тип данных в последующих действиях программы?

Если мы задали опциональный тип, то вроде бы его можно уже и использовать. На самом деле это не совсем так. Опциональные типы не взаимодействуют ни между собой, ни с другими типами данных.

Например, если мы захотели сложить две цифры, одна из которых обычный «Int», а вторая опциональный «Int?», то у нас ничего не получится. Это разные типы данных и они не взаимодействуют между собой. Чтобы их сложить необходимо вначале опциональный «Int?» привести к обычному «Int».

А ещё раньше, до того, как мы собрались складывать и приводить опциональный «Int?» к обычному»Int», нужно проверить, есть ли в опциональном «Int?» какое-то значение на данный момент. Мы помним, что программа — это набор команд, которые выполняются последовательно. По ходу выполнения программы значение любой переменной может меняться (константы в Swift само собой не меняются). А для переменных опционального типа данных значение такой переменной не просто меняется, а может и вообще отсутствовать. И если мы забудем об этом, то программа может рухнуть.

Поэтому, прежде чем выполнять любое действие с переменной, у которой опциональный тип данных, необходимо выполнить проверку: есть в ней на данный конкретный момент значение или нет. Это усложняет нам жизнь, но лучше перестраховаться, чем недосмотреть.

Как проверить, есть ли значение в переменной с опциональным типом данных?

Это сделать достаточно просто: берём оператор сравнения «if» и задаём условие. Спрашиваем: эй, переменная, ты nil или не nil?

Если она отвечает «я сейчас nil, пустая», тогда ничего от неё не требуем. Разве что можно вывести на экран информацию о том, что значение переменной сейчас отсутствует, nil. Назовём это действие чистосердечным признанием! Если же переменная не nil, тогда её можно использовать в последующих действиях. Пример:

if optSample ==nil < print ("optSample is nil") print (optSample)

В части «if» мы задаём вопрос на проверку: если он положительный, то программа сообщает нам об этом, зажигает красный свет на дальнейшее использование. Если же значение не nil, то мы уже можем выполнять с ним те или иные действия. В данном случае мы просто выводим это имеющееся значение на экран.

Да, и в песочнице будет показано, что это не простое значение, а опциональное. Мы увидим не просто «12», а «Optional(12)». Таким образом, мы проверили опциональный тип данных и узнали, есть ли там nil или нет. Если есть, мы тормозим, прекращаем работать с этим значением, а если нет, то тогда мы можем работать дальше.

Но и здесь есть свои нюансы. В частности, если просто передать это значение куда-то, то по идее это возможно. Но для операций, в которых это значение будет использоваться, взаимодействовать с другими значениями, как уже было сказано выше, необходимо привести опциональный тип данных к обычным, стандартным типам данных. Например, привести опциональный «Int?» к обычному «Int».

Как привести опциональный тип данных к обычному, неопциональному?

Для этого используется метод, который называется разворачивание: «unwrap», «unwrapped» или «unwrapping» (анрэп, анрэппед, анрэппинг). В синтаксисе для анрэпинга применяется восклицательный знак, который ставится рядом с переменной. В примере выше в части «else» можно написать следующий код:

if optSample ==nil < print ("optSample is nil") var s = optSample! + 6

После проверки на nill, если результат показывает, что nil здесь не имеет места быть, мы переходим к следующей операции. Например, нам нужно объявить новую переменную «s» и присвоить ей значение «optSample + 6». Но поскольку «optSample» у нас имеет опциональный тип данных, то мы записываем имя переменной и добавляем к нему восклицательный знак: «optSample!».

И тогда переменная «optSample» будет преобразована в неопциональный тип данных, тип её значения станет обычный «Int». После чего это значение уже может спокойно использоваться в операциях с другими значениями. В результате песочница покажет результат «18». А если этого не сделать она выдаст ошибку, что значение не развернуто.

Подвиды метода разворачивания

У этого метода разворачивания есть и свои разновидности. Пример выше называется ещё «force unwrapping». Это можно перевести как «силовое разворачивание», «вынужденное», «насильственное», «принудительное». При этом надо иметь в виду, что если мы не проверили на nil, то программа может упасть. Поэтому всегда нужно проверять. Это обязательное условие «force auwrapping».

Второй способ разворачивания — это «optional binding». Переводится как «связывание», «опциональное связывание» или «связывание опционала». Выглядит этот способ/метод следующим образом:

if var sum = optSample < sum = sum + 8 print("optSample is nill)

Этот метод работает с «if» и «while». Что происходит в этом случае? Мы пишем, что если новая переменная присваивает себе значение опциональной переменной, т.е. если это происходит, тогда мы выполняем следующее действие. Если новая переменная не может присвоить значение опциональной переменной, поскольку там нет значения, т. е. там nll, тогда программа ничего не делает, в ней ничего не делается.

Смысл такой, что дальнейшее движение происходит только тогда, когда значение извлекается из опциональной переменной и присваивается новой переменной. А у этой новой переменной тип данных устанавливается «Int». По факту, если это возможно, то двигаемся дальше. А если это не случается, то программа уходит во вторую часть условия, в «else».

Почему при этом программа не падает? Если бы мы просто написали, что новая переменная присваивает значение из опциональной, тогда бы она могла упасть. Но у нас есть оператор условия «if», который говорит: «если» значение присваивается, тогда только двигаемся дальше. Тем самым обеспечивается наличие значения, что там не nil. А если это условие не выполняется, т. е. там как раз nil, то действие переходит в «else». И там уже мы можем вывести сообщение, что здесь nill, или просто ничего не делать. И программа при этом останется в целом работоспособной. Другое дело, что значения из опциональной переменной мы не возьмём, поскольку его там нет, но и программа не упадёт.

И еще один момент, если во второй части условия мы не планируем что-то делать, то её можно и не использовать. Тогда код может выглядеть так:

if var sum = optSample < sum = sum + 8

Неявно развернутые опционалы

Есть случаи, когда nil может быть только в начале, до первого запроса, обращения к переменной. А потом всегда будут значения. Например, программа запускается, а потом после запуска значения будут всегда. В этом случае можно использовать «неявно извлечённый опционал». На английском — «Implicitly Unwrapped Optionals». Для наглядности можно написать так. Есть три типа данных с точки зрения опциональности:

  • «Int» — простой, обычный интеджер;
  • «Int?» — опциональный интеджер, который надо всё время проверять и разворачивать;
  • «Int!» — неявно извлечённый интеджер; первый раз у него есть nil, а потом гарантировано будут значения. Это значит потом его не надо проверять и разворачивать, а можно использовать как обычный «Int».

var house: Int! = nil
house = house + 7

В первой строке мы объявили переменную «house», тут же обозначили, что тип данных у неё неявный развернутый (извлечённый) опционал («Int!»). И присвоили начальное значение nil. Мы честно предупредили, что значения нет.

Затем во второй строке мы присвоили этой переменной значение «8». Обратите внимание, что нам не надо здесь проверять наличие nil и не надо разворачивать опционал в обычный тип данных «Int». Более того, мы сразу можем использовать новое значение для операции с другими значениями типа «Int».

Всё это возможно благодаря тому, что в неявно извлечённом опционале заранее предусмотрено, что первое значение у него nil, а потом всегда будут обычные, не опциональные значения. Всё это происходит само собой, поскольку предусмотрено в свойствах данного типа данных (неявно извлечённого опционала).

И обратим внимание на восклицательный знак (!). В одном случае он используется для разворачивания опционала («force unwrapping»), а во втором он фиксирует определённый подвид, разновидность опционала («неявно развёрнутый опционал»). И то, и другое близко по смыслу, есть только некоторые нюансы. В первом случае, это как бы отдельная, дискретная операция, во втором — это уже более постоянная характеристика типа данных.

Резюме по опционалам

1. Опциональный тип данных — это такой тип данных, где может не быть значения. Пример ситуации — сбой в работе сервера, отсутствие ответа.

2. Синтаксис — опциональный тип данных обозначается вопросительным знаком («Int?»).

3. Чтобы использовать значение из опционала сначала нужно проверить, что оно там есть. Это делается с помощью логического оператора «if». И далее, нужно преобразовать опциональный тип данных в обычный тип данных. Это можно сделать двумя способами:

  • force unwrapping — силовое разворачивание, когда к названию переменной добавляется восклицательный знак («optSample!»);
  • optional binding — связывание опционала, когда значение опциональной переменной присваивается новой переменной и это оформляется как первая часть условия «if».

4. «Неявно извлечённые опционалы» — это такие опционалы, которые не имеют значения до первого обращения к ним, а потом гарантированно имеют значения. Их можно обозначить восклицательным знаком, и после получения первого обычного значения их не нужно проверять на nil и можно использовать как обычные, не опциональные типы для взаимодействия с другими значениями того же типа.

Утверждения

Ещё одна небольшая тема, по смыслу связанная с опционалами.

Asserts — это некие утверждения, которые проверяют условия и в зависимости от результата проверки или останавливают программу, или позволяют ей дальше работать. Чем ассерты отличаются от опционалов? Опционал позволяет определить, есть значение или нет, и писать код, который будет корректно работать в ситуации, когда значения нет. Однако бывает так: если значения нет, то программа не может выполняться, даже если мы готовы написать корректный код. Или программа не может выполняться, если значение не соответствует определённым условиям.

Пример: мы хотим посчитать сколько продано товаров за день, а в программу не введена стоимость товара (значения нет). Или, мы считаем сколько пива куплено в пятницу, а для подсчёта указан день недели четверг (т. е. значение есть, но не которое нужно).

В таких случаях мы пишем «assert», утверждение, некую команду, которая по ходу проверяет работоспособность программы. Обычно оно содержит в себе проверку истинности условия. Если условие соблюдается, т. е. возвращается «true», то программа продолжается дальше. Если нет, то программа останавливается. При этом в консоль может выводиться определённое сообщение. Это удобно тем, что в этом сообщении может указываться невыполненное условие (это не обязательно, но полезно). А также тем, что утверждение показывает место в коде, где произошел сбой.

Как выглядит утверждение, синтаксис? На английском — «assert, asserts». Пример кода ниже:

let age = -3
assert(age >= 0, «Возраст человека не может быть меньше нуля»)

В данном случае у нас есть константа «age» (возраст), которая содержит ошибочное отрицательное значение «-3». По смыслу уже понятно, что «-3» не может быть возрастом.

Далее разработчик для предупреждения подобных ошибок, а точнее для их отлавливания, использует утверждение: если age >= 0 (возраст больше или равен нулю), то всё нормально и двигаемся дальше. В противном же случае, во-первых, программа остановится, а во-вторых, на экране (в консоли) появится сообщение: «Возраст человека не может быть меньше нуля».

А если сообщение нам не нужно, то можно написать и так:

assert(age>=0)

Насколько это важно? Говорят, что начинающим программистам это не очень понадобится. И что чаще это нужно в процессе разработки, чтобы знать, где программа может рухнуть и как можно отловить ошибку. Например, это полезно использовать при написании своих библиотек, фреймворков. В любом случае, фича интересная. И возможно когда-нибудь может понадобиться.

Итак, перед вами своеобразный альтернативный вариант изложения главы из учебника Swift про опциональные типы данных. На первый взгляд тема довольно сложная, но когда посидишь над ней и попытаешься сам систематизировать, то получается уже яснее и понятнее.

А как вы поняли тему про опционалы? Какие ещё, возможно, здесь есть подводные камни?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *