HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-03-10
1 <p>Теги: ios, swift, программирование на ios, label statements, разработка на ios, control flow statements</p>
1 <p>Теги: ios, swift, программирование на ios, label statements, разработка на ios, control flow statements</p>
2 <p>Перед написанием данной статьи я спросил в нескольких iOS-чатах про эту фичу Swift, однако никто из iOS-разработчиков вообще(!) не знал о существовании<strong>Label Statements</strong>. В одной из прошлых<a>заметок</a>, где мы разбирали, какие есть типы Предписаний (Statements) в Swift, были упомянуты<strong>Control Flow Statements</strong>. Вот именно на управляющие потоком выполнения предписания и можно поставить<strong>лейблы</strong>.</p>
2 <p>Перед написанием данной статьи я спросил в нескольких iOS-чатах про эту фичу Swift, однако никто из iOS-разработчиков вообще(!) не знал о существовании<strong>Label Statements</strong>. В одной из прошлых<a>заметок</a>, где мы разбирали, какие есть типы Предписаний (Statements) в Swift, были упомянуты<strong>Control Flow Statements</strong>. Вот именно на управляющие потоком выполнения предписания и можно поставить<strong>лейблы</strong>.</p>
3 <h2>Зачем?</h2>
3 <h2>Зачем?</h2>
4 <p>Некоторые сравнивают<strong>Label Statements</strong>с некоторой "огламуренной" разновидностью GOTO. Нагляднее всего это можно показать на двух вложенных Control Flow Statements, например на циклах:</p>
4 <p>Некоторые сравнивают<strong>Label Statements</strong>с некоторой "огламуренной" разновидностью GOTO. Нагляднее всего это можно показать на двух вложенных Control Flow Statements, например на циклах:</p>
5 let arrVeggies = ["eggplant", "cauliflower", "potato"] let arrColors = [0xffffff, 0x000000] vegLabel: for veg in arrVeggies { print(veg) for col in arrColors { if veg == "cauliflower" &amp;&amp; col == 0x000000 { continue vegLabel } print(String(col, radix: 16)) } }<p>Перед первым циклом мы вставили vegLabel. Это дало нам возможность вызвать во втором цикле continue vegLabel, что продолжило выполнение arrVeggies. В итоге мы получили такой результат:</p>
5 let arrVeggies = ["eggplant", "cauliflower", "potato"] let arrColors = [0xffffff, 0x000000] vegLabel: for veg in arrVeggies { print(veg) for col in arrColors { if veg == "cauliflower" &amp;&amp; col == 0x000000 { continue vegLabel } print(String(col, radix: 16)) } }<p>Перед первым циклом мы вставили vegLabel. Это дало нам возможность вызвать во втором цикле continue vegLabel, что продолжило выполнение arrVeggies. В итоге мы получили такой результат:</p>
6 eggplant ffffff 0 cauliflower ffffff potato ffffff 0<p>На реальных проектах таким образом вы сможете оптимизировать производительность сложных вложенных циклов.</p>
6 eggplant ffffff 0 cauliflower ffffff potato ffffff 0<p>На реальных проектах таким образом вы сможете оптимизировать производительность сложных вложенных циклов.</p>
7 <h2>Давайте ещё рассмотрим пример с break</h2>
7 <h2>Давайте ещё рассмотрим пример с break</h2>
8 <p>Работая в геймдеве, мне часто приходилось обходить 2-х мерные массивы, которые являются представлением 2D карты:</p>
8 <p>Работая в геймдеве, мне часто приходилось обходить 2-х мерные массивы, которые являются представлением 2D карты:</p>
9 // ┌──▶ x // │ // ▼ // y let treasureIsland4x4 = [ ["empty", "empty", "empty", "empty"], ["empty", "empty", "empty", "empty"], ["empty", "empty", "empty", "empty"], ["treasure", "empty", "empty", "empty"] ] yScan: for (y, xRow) in treasureIsland4x4.enumerated() { // x Scan for (x, value) in xRow.enumerated() { if value == "treasure" { print("Found at x=\(x), y=\(y)") break yScan } } }<p>Результат будет:</p>
9 // ┌──▶ x // │ // ▼ // y let treasureIsland4x4 = [ ["empty", "empty", "empty", "empty"], ["empty", "empty", "empty", "empty"], ["empty", "empty", "empty", "empty"], ["treasure", "empty", "empty", "empty"] ] yScan: for (y, xRow) in treasureIsland4x4.enumerated() { // x Scan for (x, value) in xRow.enumerated() { if value == "treasure" { print("Found at x=\(x), y=\(y)") break yScan } } }<p>Результат будет:</p>
10 <p>Массив мы предопределили литералами и "закопали" сокровище в начале последнего вложенного x массив. Если во вложенном цикле мы напишем<strong>break</strong>, то мы просто выйдем из x Scan цикла и нам придётся писать или условие со вторым break, или отдельную функцию с<strong>return</strong>.</p>
10 <p>Массив мы предопределили литералами и "закопали" сокровище в начале последнего вложенного x массив. Если во вложенном цикле мы напишем<strong>break</strong>, то мы просто выйдем из x Scan цикла и нам придётся писать или условие со вторым break, или отдельную функцию с<strong>return</strong>.</p>
11 <p>Благодаря<strong>Label Statement</strong>мы сразу прерываем первый цикл. При написании оптимизированных алгоритмов вложенность бывает выше 2-х мерной и лейблы нам помогут сделать выполнение быстрее, а код короче.</p>
11 <p>Благодаря<strong>Label Statement</strong>мы сразу прерываем первый цикл. При написании оптимизированных алгоритмов вложенность бывает выше 2-х мерной и лейблы нам помогут сделать выполнение быстрее, а код короче.</p>
12 <p>Кроме циклов, лейблы можно ставить и на другие<a>Control Flow Statements</a>: На<strong>while-циклы</strong>:</p>
12 <p>Кроме циклов, лейблы можно ставить и на другие<a>Control Flow Statements</a>: На<strong>while-циклы</strong>:</p>
13 whileLabel: while condition == true { … }<p>На<strong>repeat-while-циклы</strong>:</p>
13 whileLabel: while condition == true { … }<p>На<strong>repeat-while-циклы</strong>:</p>
14 repeatLabel: repeat { … } while condition == true<p>На<strong>if-предписание</strong>:</p>
14 repeatLabel: repeat { … } while condition == true<p>На<strong>if-предписание</strong>:</p>
15 ifLabel: if condition == true { … }<p>На<strong>switch-предписание</strong>:</p>
15 ifLabel: if condition == true { … }<p>На<strong>switch-предписание</strong>:</p>
16 switchLabel: switch condition { … }<p><em>Остались вопросы? Пишите их в комментариях!</em></p>
16 switchLabel: switch condition { … }<p><em>Остались вопросы? Пишите их в комментариях!</em></p>
17  
17