В предыдущих статьях вы изучили некоторые основные понятия языка программирования Swift. Если вы программировали раньше, я уверен, что вы видели несколько сходств с другими языками программирования, такими как Ruby, JavaScript и Objective-C.
В этой статье мы увеличим поток управления в Swift. Прежде чем мы сможем обсудить поток управления более подробно, нам нужно взглянуть на концепцию, которая является новой для большинства из вас, опциональные. Дополнительные функции являются еще одной функцией безопасности Swift. Поначалу может показаться хлопотным использование опций, но вы быстро поймете, что опционы сделают ваш код намного безопаснее.
1. Необязательные
Мы уже видели, что переменная должна быть инициализирована, прежде чем ее можно будет использовать. Посмотрите на следующий пример, чтобы лучше понять, что это значит.
1
2
3
|
var str: String
str.isEmpty
|
Если вы привыкли работать со строками в Objective-C, то можете удивиться, что Swift покажет вам ошибку. Давайте посмотрим, что говорит нам эта ошибка.
Во многих языках переменные имеют начальное значение по умолчанию. Например, в Objective-C строка в следующем фрагменте кода равна nil
.
1
|
NSString *newString;
|
Тем не менее, концепция nil
отличается в Swift и Objective-C. Мы обсудим nil
более подробно чуть позже.
Что является необязательным?
Swift использует опции для инкапсуляции важной концепции, то есть переменная или константа имеет значение или не имеет. Это так просто в Swift. Чтобы объявить переменную или константу необязательной, мы добавляем знак вопроса к типу переменной или константы.
1
|
var str: String?
|
Переменная str
больше не имеет тип String
. Теперь это тип необязательный String
. Это важно понимать. Результатом или побочным эффектом является то, что мы больше не можем напрямую взаимодействовать со значением переменной str
. Значение безопасно хранится в необязательном параметре, и нам нужно запросить необязательное значение, которое оно инкапсулирует.
Принудительная распаковка
Один из способов получить доступ к значению необязательного параметра — принудительная распаковка. Мы можем получить доступ к значению переменной str
, добавив !
на имя переменной.
1
2
3
4
5
|
var str: String?
str = «Test»
print(str!)
|
Важно, чтобы вы были уверены, что необязательный параметр содержит значение, когда вы его принудительно разворачиваете. Если у необязательного значения нет значения, и вы принудительно развернули его, Swift выдаст вам ошибку.
Дополнительное связывание
Существует более безопасный способ получить доступ к значению необязательно. Мы рассмотрим внимательнее операторы if
через несколько минут, но в следующем примере показано, как мы можем безопасно обращаться к значению, хранящемуся в переменной str
, которая имеет тип необязательный String
.
1
2
3
4
5
6
7
|
var str: String?
if str != nil {
print(str!)
} else {
print(«str has no value»)
}
|
Сначала мы проверяем, равна ли переменная str
nil
прежде чем печатать ее содержимое. В этом примере str
не имеет значения, что означает, что оно не будет принудительно развернуто случайно.
Есть более элегантный подход, называемый необязательным связыванием. В следующем примере мы присваиваем значение, хранящееся в необязательном порядке, временной константе, которая используется в операторе if
. Значение необязательного str
связано с константой strConst
и используется в операторе if
. Этот подход также работает для операторов while
.
1
2
3
4
5
6
7
8
9
|
var str: String?
str = «Test»
if let strConst = str {
print(strConst)
} else {
print(«str has no value»)
}
|
Что такое nil
?
Если вы пришли из Objective-C, то вы наверняка знаете, что такое nil
. В Objective-C nil
— указатель на объект, который не существует. Swift определяет nil
немного по-другому, и важно, чтобы вы понимали разницу.
В Swift nil
означает отсутствие значения, любое значение. В то время как nil
применим только к объектам в Objective-C, в Swift nil
может использоваться для любого типа. Поэтому важно понимать, что необязательный не эквивалентен nil
в Objective-C. Эти понятия очень разные.
2. Контроль потока
Swift предлагает ряд общих конструкций для управления потоком кода, который вы пишете. Если у вас есть опыт программирования, то у вас не if
проблем с ускорением при помощи конструкций потока управления Swift, условных операторов if
и switch
, а также циклов for
и while
.
Однако Swift не был бы Swift, если бы его поток управления не отличался, например, от конструкций потока управления Objective-C. Хотя детали важны, я уверен, что они не помешают вам освоиться со Swift. Давайте начнем с наиболее распространенной условной конструкции, оператора if
.
if
Операторы if
Swift очень похожи на те, что содержатся в Objective-C. Основное отличие состоит в том, что нет необходимости заключать условие в скобки. Однако фигурные скобки обязательны. Последнее не позволяет разработчикам вводить типичные ошибки, связанные с записью операторов if
без фигурных скобок. Вот как выглядит выражение if
в Swift.
1
2
3
4
5
6
7
|
let a = 10
if a > 10 {
print(«The value of \»a\» is greater than 10.»)
} else {
print(«The value of \»a\» is less than or equal to 10.»)
}
|
Неудивительно, что Swift также определяет предложение else
. Код в предложении else
выполняется, если условие равно false
. Также возможно связать операторы if
как показано в следующем примере.
1
2
3
4
5
6
7
8
9
|
let a = 10
if a > 10 {
print(«The value of \»a\» is greater than 10.»)
} else if a > 5 {
print(«The value of \»a\» is greater than 5.»)
} else {
print(«The value of \»a\» is less than or equal to 5.»)
}
|
Следует сделать одно важное замечание: условие if
должно возвращать true
или false
. Это не так для утверждений if
в Objective-C. Взгляните на следующее утверждение if
в Objective-C.
1
2
3
4
5
6
7
|
NSArray *array = @[];
if (array.count) {
NSLog(@»The array contains one or more items.»);
} else {
NSLog(@»The array is empty.»);
}
|
Если бы мы перенесли приведенный выше фрагмент кода на Swift, мы бы столкнулись с ошибкой. Ошибка не очень информативна, но Swift действительно говорит нам, что нам нужно убедиться, что результат условия оценивается как true
или false
.
Правильный способ перевести приведенный выше фрагмент Objective C в Swift — убедиться, что условие оператора if
значение true
или false
, как в следующем фрагменте.
1
2
3
4
5
6
7
|
let array = [String]()
if array.count > 0 {
print(«The array contains one or more items.»)
} else {
print(«The array is empty.»)
}
|
switch
Оператор switch
Swift более мощный, чем его эквивалент Objective-C. Это также безопаснее, как вы узнаете через мгновение. Хотя есть некоторые различия, операторы switch
в Swift придерживаются той же концепции, что и в других языках программирования; значение передается в оператор switch
и сравнивается с возможными шаблонами сопоставления.
Это верно, шаблоны. Как я уже сказал, оператор switch
в Swift имеет несколько хитростей. Мы посмотрим на эти трюки в данный момент. Давайте сначала поговорим о безопасности.
исчерпывающий
Оператор switch
в Swift должен быть исчерпывающим, а это означает, что каждое возможное значение типа, передаваемого в оператор switch
должно обрабатываться оператором switch
. Как и в Objective-C, это легко решить, добавив регистр по default
, как показано в следующем примере.
01
02
03
04
05
06
07
08
09
10
|
let a = 10
switch a {
case 0:
print(«a is equal to 0»)
case 1:
print(«a is equal to 1»)
default:
print(«a has another value»)
}
|
Проваливаться
Важным отличием реализации Objective-C операторов switch
является отсутствие неявного падения. Следующий пример не работает в Swift по нескольким причинам.
1
2
3
4
5
6
7
8
9
|
let a = 10
switch a {
case 0:
case 1:
print(«a is equal to 1»)
default:
print(«a has another value»)
}
|
Первый случай, в котором a
сравнивается с 0
, неявно не относится ко второму случаю, в котором a
сравнивается с 1
. Если вы добавите приведенный выше пример на игровую площадку, вы заметите, что Swift выдает ошибку. Ошибка говорит о том, что в каждом случае должен быть хотя бы один исполняемый оператор.
Обратите внимание, что случаи оператора switch
не включают операторы break для выхода из оператора switch
. Это не требуется в Swift, поскольку в Swift не существует неявного падения. Это позволит устранить ряд распространенных ошибок, вызванных непреднамеренным провалом.
Узоры
Сила оператора switch
в Swift заключается в сопоставлении с образцом. Взгляните на следующий пример, в котором я использовал диапазоны для сравнения рассматриваемого значения с.
01
02
03
04
05
06
07
08
09
10
|
let a = 10
switch a {
case 0..<5:
print(«The value of a lies between 0 and 4.»)
case 5…10:
print(«The value of a lies between 5 and 10.»)
default:
print(«The value of a is greater than 10.»)
}
|
Оператор ..<
или оператор полуоткрытого диапазона определяет диапазон от первого значения до второго значения, исключая второе значение. Оператор ...
или оператор закрытого диапазона определяет диапазон от первого значения до второго значения, включая второе значение. Эти операторы очень полезны в широком диапазоне ситуаций.
Вы также можете сравнить рассматриваемое значение оператора switch
с кортежами. Посмотрите на следующий пример, чтобы увидеть, как это работает.
01
02
03
04
05
06
07
08
09
10
11
12
|
let latlng = (34.15, -78.03)
switch latlng {
case (0, 0):
print(«We’re at the center of the planet.»)
case (0…90, _):
print(«We’re in the Northern hemisphere.»)
case (-90…0, _):
print(«We’re in the Southern hemisphere.»)
default:
print(«The coordinate is invalid.»)
}
|
Как вы можете видеть в приведенном выше примере, возможно, что значение соответствует более чем одному случаю. Когда это происходит, выбирается первый подходящий случай. Приведенный выше пример также иллюстрирует использование подчеркивания. Как мы видели в предыдущей статье , мы можем использовать подчеркивание _
, чтобы указать Swift, какие значения нам не интересны.
Привязка значений
Привязка значений также возможна с помощью операторов switch
, как показано в следующем примере. Второе значение кортежа временно связано с description
константы для использования в первом и втором случае.
01
02
03
04
05
06
07
08
09
10
|
var response = (200, «OK»)
switch response {
case (200..<400, let description):
print(«The request was successful with description \(description).»)
case (400..<500, let description):
print(«The request was unsuccessful with description \(description).»)
default:
print(«The request was unsuccessful with no description.»)
}
|
for
Цикл for
— это первая конструкция цикла, которую мы рассмотрим. Он ведет себя очень похоже for
циклы for
в других языках. Раньше было два вкуса: цикл for
цикл for-in
. Начиная с Swift 3, однако, петли в стиле C больше не доступны. Следующий фрагмент не возможен в Swift 3.
1
2
3
|
for var i = 0;
print(«i is equal to \(i).»)
}
|
Если вы вставите этот фрагмент на игровую площадку, вы также заметите, что операторы ++
и --
больше не доступны в Swift 3.
Цикл for-in
идеально подходит для циклического просмотра содержимого диапазона или коллекции. В следующем примере мы зациклились на элементах массива.
1
2
3
4
5
|
let numbers = [1, 2, 3, 5, 8]
for number in numbers {
print(«number is equal to \(number)»)
}
|
Мы также можем использовать циклы for-in
для циклического перебора пар ключ-значение в словаре. В следующем примере мы объявляем словарь и выводим его содержимое на консоль. Как мы видели ранее в этой серии, последовательность пар ключ-значение не определена, поскольку словарь представляет собой неупорядоченный набор пар ключ-значение.
1
2
3
4
5
|
var bids = [«Tom»: 100, «Bart»: 150, «Susan»: 120]
for (name, bid) in bids {
print(«\(name)’s bid is $\(bid).»)
}
|
Каждая пара ключ-значение словаря доступна for-in
цикле for-in
в виде набора именованных констант. Петля for-in
также отлично сочетается с диапазонами. Я уверен, что вы согласны с тем, что приведенный ниже фрагмент легко читается и понимается благодаря использованию закрытого диапазона.
1
2
3
|
for i in 1…10 {
print(«i is equal to \(i)»)
}
|
while
Цикл while может быть двух видов: while
и repeat-while
. Основное отличие состоит в том, что набор операторов цикла repeat-while
while всегда выполняется хотя бы один раз, поскольку условие repeat-while
оценивается в конце каждой итерации. Следующий пример иллюстрирует эту разницу.
01
02
03
04
05
06
07
08
09
10
|
var c = 5
var d = 5
while c < d {
print(«c is smaller than d»)
}
repeat {
print(«c is smaller than d»)
} while c < d
|
Оператор print цикла while никогда не выполняется, тогда repeat-while
цикл repeat-while
while выполняется один раз.
Во многих случаях циклы for
могут быть переписаны как циклы while
, и часто разработчик сам определяет, какой тип цикла использовать в конкретной ситуации. Следующие циклы for
и while
дают одинаковый вывод.
01
02
03
04
05
06
07
08
09
10
|
for i in 0..<10 {
print(i)
}
var i = 0
while i < 10 {
print(i)
i += 1
}
|
Вывод
В Swift гораздо больше возможностей для управления потоком, чем то, что мы рассмотрели в этой статье, но теперь у вас есть базовое понимание, чтобы продолжить свое путешествие в Swift. Я надеюсь, что этот урок показал вам, как реализация потока управления Swift очень похожа на реализацию других языков программирования — но с изюминкой.
В оставшейся части этой серии мы будем чаще использовать конструкции потока управления Swift, и вы постепенно будете лучше понимать тонкие различия между Swift и такими языками, как Objective-C. В следующей части этой серии мы начнем изучать функции.
Если вам нужен быстрый способ начать создавать приложения на языке Swift, у нас есть курс для этого!
Или ознакомьтесь с некоторыми другими нашими учебными пособиями и курсами по разработке Swift и iOS!