В контексті програмування термін «потік» — це процес виконання програми. У Swift існують спеціальні механізми, які дозволяють керувати цим процесом, наприклад виконувати або, навпаки, ігнорувати код в залежності від заданих умов, а також багаторазово повторювати певні блоки коду.
Вміння управляти ходом роботи програми — дуже важливий аспект програмування на мові Swift, завдяки якому програми можуть виконувати різні блоки коду залежно від умов, що виникли. Сьогодні ми розглянемо механізми, які підтримуються практично усіма мовами програмування і без яких неможливе виконання жодної програми.
Умовний оператор if
Іноді потрібно запустити код, який буде виконуватися лише в певних умовах. Swift дає нам таку можливість у вигляді умовного оператора if-else
. У разі його застосування блок коду у фігурних скобках виконається, якщо перевірка умови поверне значення true (істина).
Досить часто, виходячи з логіки продовження роботи програми, можна створювати false (хибне) значення перевірки умови не тільки в простих, але й у більш складних конструкціях умовного оператора if-if
else-if else-else
.
«Умова» — це логічний вираз. Він може приймати значення true (істина) або false (брехня). Для зберігання таких значень в Swift передбачено фундаментальний тип даних Bool, який ми розглядали в статті про типи даних у Swift.
«Блок коду» — це фрагмент коду, розміщений всередині фігурних дужок {}. На відміну від Objective-C, використання круглих дужок навколо умови є опціональним, а ось фігурні дужки обов’язкові навіть у тих випадках, коли потрібно виконати всього один рядок коду:
var action: String var person ="hater" if person =="hater"{ action ="hate"}
У цьому прикладі оператор порівняння «==» використовується в складі умовного оператора для перевірки на відповідність значення hater
змінної person
. Якщо результат порівняння дорівнює true (істина) змінна action
отримає нове значення hate
.
Давайте познайомимося з іншими видами умовного оператора:
var action: String var person ="hater" if person =="hater"{ action ="hate"}elseif person =="player"{ action ="play"}else{ action ="cruise"}
У результаті виконання цього коду змінна action
набуде одного з трьох можливих значень: hate
, play
або cruise
.
Перевірка декількох умов
Умовний оператор if
пропонує також розширений синтаксис запису, який об’єднує кілька операторів if
, дозволяючи задавати будь-яку кількість умов.
Для подальшого успішного виконання блоку коду необхідно, щоб такий складний умовний оператор повертав значення true (істина). Для його реалізації використовується оператор «&&» — логічне «І». Наприклад:
var action: String var stayOutTooLate =true var nothingInBrain =true if stayOutTooLate && nothingInBrain { action ="cruise"}
Оскільки змінні stayOutTooLate
і nothingInBrain
містять початкові значення true (істина), результатом перевірки складеної умови стане привласнення змінній action
нового значення cruise
.
Важливо: для підвищення продуктивності Swift використовує технологію під назвою «скорочені обчислення»: перевірка складеної умови на відповідність значенню true (істина) автоматично припиняється при виявленні першої відповіді false (брехня)!
Тернарний умовний оператор
Для зручності Swift дозволяє скоротити стандартну форму запису оператора if
всього до кількох символів. Така форма називається тернарним умовним оператором:
умова ? код_1 : код_2
Цей оператор може виконати один з двох блоків коду в залежності від отриманного значення заданої умови. Знак «?» відокремлює код від умови. Самі ж блоки коду розділяються між собою двокрапкою «:». Якщо результат перевірки заданої умови дорівнює true (істина), виконується перший блок коду код_1
. У всіх інших випадках виконується другий блок код_2
.
Оператор if
для опціоналів
Конструкція if-else
надає значно ширші можливості для розробки програм і, що найважливіше, дозволяє уникнути помилок, коли необхідно отримати значення для пустого опціонала:
Наведений приклад дозволяє визначити факт присутності тролів, про що говорить значення змінної trollsCount
. Якщо тролів немає, у консолі виводиться відповідне повідомлення. В іншому випадку обчислюється, скільки котлів для тролів необхідно придбати.
Зверніть увагу, що при обчисленні значення allPotsCount
використовується метод примусового визначення опціонального значення змінної trollsCount
.
Цей спосіб перевірки існування значення опціонала працює виключно при примусовому вилученні опціонального значення, оскільки таке значення не повинно бути nil, а отже не має сенсу порівнювати його з nil.
В рамках використання конструкції if-else
для перевірки існування значення в опціонала ми можемо спробувати витягти його і призначити новому параметру. В цьому випадку, якщо значення опціонала існує, то буде створено новий параметр, який отримає витягнуте опціональне значення. Якщо ж значення опціонала дорівнює nil, то спроба ініціалізації не відбудеться.
Цей прийом носить назву опціонального зв’язування (optional binding).
При опціональному зв’язуванні в операторі if відбувається автоматичне вилучення значення змінної monstersCount
, а оскільки воно існує, відбувається ініціалізація змінної monsters
отриманим значенням.
Зверніть увагу, що змінна monsters
, створена поза умовним оператором і інша змінна monsters
, створена в процесі опціонального зв’язування — це різні змінні. Змінна, створена при опціональному зв’язуванні, є локальною для умовного оператора, тому використовувати її можна тільки всередині даного оператора. При цьому глобальна змінна monsters
не змінюється, про що свідчить кінцеве значення цієї змінної в кінці лістингу.
Якби в змінної monstersCount
не існувало початкового значення, то управління перейшло б до блоку else
.
Виключення з правил
Основним правилом для застосування умовних операторів є те, що результатом перевірки умови завжди має виступати значення true (істина). Іноді, щоб домогтися відповідності виконання цього твердження рекомендується використовувати оператор заперечення «!» для перетворення значення false (брехня) на протилежне.
if!stayOutTooLate && !nothingInBrain { action ="cruise"}
Застосування оператора «!» виправдано, якщо обидві змінні stayOutTooLate
і nothingInBrain
мають початкові значення false (брехня), в такому випадку результатом перевірки умовного оператора стане true (істина).
Оператор guard
Оператор guard
називається оператором раннього виходу. Подібно оператору if
він перевіряє істинність заданої йому умови. Відмінність його роботи полягає у тому, що блок коду виконується тільки в тому випадку, якщо результат перевірки умови дорівнює значенню false.
Якщо умова оператора guard
виконується, то виконання коду передається після закриваючої дужки guard
. Всі змінні і константи, яким було присвоєно значення з використанням опціонального зв’язування в якості частини умови guard
, доступні до кінця області, в якій було визначено оператор guard
.
Якщо ж умова не виконується, то виконується код всередині else
. Ця гілка повинна перекинути виконання коду на вихід з блоку коду, в якому було визначено guard. Зробити це можна за допомогою операторів return
, break
, continue
, throw
або викликати метод, який нічого не повертає, наприклад fatalError()
.
Оператори діапазону
У Swift існують спеціальні оператори, за допомогою яких можна об’єднувати безліч послідовних числових значень (наприклад, 1, 2, 3, 4), тобто створювати діапазони (наприклад, від 1 до 4).
Такі оператори називаються операторами діапазону (range operators).
Swift пропонує два оператора діапазону:
- Закритий оператор: a...b визначає діапазон, який включає всі числа від a до b, включаючи a і b. Наприклад, для чисел цілого типу діапазон 1…4 включає в себе числа 1, 2, 3, 4.
- Напіввідкритий оператор: a..<b визначає діапазон чисел від a до b, включаючи тільки a. Наприклад, для чисел цілого типу діапазон 2..<5 включає в себе числа 2, 3, 4.
Оператор розгалуження switch
Інколи потрібно реалізувати велику кількість різних варіантів виконання коду в залежності від можливого значення параметра. Звичайно ж, для цього можна використовувати розширений синтаксис оператора if
, багато разів повторюючи блоки else-if
. Однак подібний підхід вносить плутанину в код і тому є поганою практикою.
Для виконання цього завдання у Swift є оператор розгалуженняswitch
, що дозволяє, так само як if
, в залежності від значення заданого виразу вибрати відповідний блок коду. Основна відмінність в тому, що switch
дає можливість працювати не тільки з логічним типом даних. Він може приймати для перевірки параметр довільного типу.
Конструкція switch-case
повинна бути вичерпною, тобто містити інформацію про всі можливі значеннях параметра. Це забезпечується, в тому числі, наявністю блоку default
. Якщо цей блок не повинен містити ніякого виконуваного коду, просто розмістіть в ньому оператор break
.
Перший варіант у switch
включає в себе всі голосні англійського алфавіту в нижньому регістрі. Аналогічно, другий варіант включає в себе всі приголосні англійського алфавіту в нижньому регістрі.
Кортежі в операторі switch
Swift використовує кортежі у якості вхідного параметра для конструкцій switch-else
. При цьому значення в блоці case
необхідно вказувати точно так само, як пишеться значення самого кортежа, тобто в дужках, де елементи розділені комами. Кожен елемент кортежу може бути перевірений за допомогою довільного значення або діапазону значень. Щоб пропустити елемент можна використовувати символ нижнього підкреслення «_» на місці будь-якого елемента.
Для того, щоб застосувати зв’язування значень для всіх елементів масиву, необхідно після оператора let
(або var
) в дужках вказати імена локальних параметрів, які будуть ініціалізовані значеннями кортежу. Після цього, як і при зв’язуванні окремих значень, після ключового слова where
вказуються умови виконання коду з блоку case
.
Сьогодні ми дізналися про:
- Умовний оператор
if
- Оператори діапазону
- Тернарний умовний оператор
- Оператор
guard
- Оператор розгалуження
switch
і кортежі в ньому
До наступних публікацій!
Джерело: Hacking with Swift
Читати ще: Основи Swift. Цикли
Потрібен MVP, розробка під iOS, Android або прототип додатка? Ознайомтеся з нашим портфоліо і зробіть замовлення вже сьогодні!