Перечисления являются общим шаблоном проектирования во многих языках программирования. Хотя вы, возможно, знакомы с перечислениями в C и Objective-C, реализация перечислений в Swift значительно более мощная и гибкая. В этом кратком совете вы узнаете, что особенного в перечислениях в Swift, как их использовать в ваших проектах и что делает их такими мощными.
1. Что такое перечисление?
Перечисления не новы и, конечно же, они не уникальны для Swift. Однако, если вы знакомы с перечислениями в C, то вам понравится мощный взгляд Swift на перечисления.
Если перечисления или перечисления являются новыми для вас, то вы можете не знать, что они могут предложить. В Swift перечисления являются первыми типами классов, которые определяют список возможных значений для этого типа.
Примером могут быть возможные состояния сетевого подключения. Возможные состояния могут быть:
- несвязно
- соединительный
- связано
Мы могли бы добавить четвертое состояние для случая, когда состояние неизвестно. Имея в виду этот пример, давайте посмотрим, как определить и реализовать такое перечисление.
основы
Как я уже сказал, перечисления являются первоклассными типами в Swift. Определение перечисления выглядит очень похоже на определение класса или структуры. В приведенном ниже примере мы определяем перечисление ConnectionState .
|
1
2
3
|
enum ConnectionState {
}
|
Имя перечисления предшествует ключевому слову enum за которым следует пара фигурных скобок. Перечисление ConnectionState определяет возможные состояния сетевого подключения. Чтобы определить эти состояния, мы добавляем значения членов или члены к определению перечисления. Определение значения члена всегда начинается с ключевого слова case .
|
1
2
3
4
5
6
|
enum ConnectionState {
case Unknown
case Disconnected
case Connecting
case Connected
}
|
В C или Objective-C приведенное выше перечисление будет выглядеть немного иначе, как показано в примере ниже. Каждое значение перечисления соответствует целому числу, например, ConnectionStateUnknown равно 0 , ConnectionStateDisconnected равно 1 и т. Д.
|
1
2
3
4
5
6
|
typedef enum : NSUInteger {
ConnectionStateUnknown,
ConnectionStateDisconnected,
ConnectionStateConnecting,
ConnectionStateConnected
} ConnectionState;
|
Это не правда в Swift. Члены перечисления не соответствуют автоматически целочисленным значениям. Члены перечисления ConnectionState сами являются значениями и имеют тип ConnectionState . Это делает работу с перечислениями более безопасной и более явной.
Сырые ценности
Можно явно указать значения членов перечисления. В следующем примере члены перечисления ConnectionState имеют необработанное значение типа Int . Каждому члену присваивается необработанное значение, соответствующее целому числу.
|
1
2
3
4
5
6
|
enum ConnectionState: Int {
case Unknown = -1
case Disconnected = 0
case Connecting = 1
case Connected = 2
}
|
Обратите внимание, что мы указываем тип необработанных значений в определении перечисления и что никакие два значения-члена не могут иметь одинаковое необработанное значение. Если мы указываем только значение для Unknown члена, Swift автоматически увеличивает значение Unknown члена и присваивает уникальные значения другим членам перечисления. Чтобы лучше проиллюстрировать это, приведенный ниже пример идентичен предыдущему определению перечисления ConnectionState .
|
1
2
3
4
5
6
|
enum ConnectionState: Int {
case Unknown = -1
case Disconnected
case Connecting
case Connected
}
|
2. Работа с перечислениями
инициализация
Использование перечисления ConnectionState аналогично использованию любого другого типа в Swift. В следующем примере мы объявляем переменную connectionState и устанавливаем для нее значение ConnectionState.Connecting .
|
1
|
var connectionState = ConnectionState.Connecting
|
Значением connectionState является ConnectionState.Connecting а переменная имеет тип ConnectionState .
Вывод типа Swift очень удобен при работе с перечислениями. Поскольку мы объявили connectionState как тип ConnectionState , теперь мы можем назначить новое значение, используя сокращенный синтаксис точки для перечислений.
|
1
|
connectionState = .Connected
|
Контроль потока
Использовать перечисления в операторе if или switch просто. Помните, что операторы switch должны быть исчерпывающими. При необходимости добавьте регистр по default .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
enum ConnectionState {
case Unknown
case Disconnected
case Connecting
case Connected
}
var connectionState = ConnectionState.Connecting
connectionState = .Connected
switch connectionState {
case .Disconnected:
println(«Disconnected»)
case .Connecting:
println(«Connecting»)
case .Connected:
println(«Connected»)
default:
println(«Unknown State»)
}
|
В следующем примере показано, как можно использовать перечисление ConnectionState . Также показано, как получить доступ к связанному значению члена перечисления. Функция canConnect принимает экземпляр ConnectionState и возвращает Bool .
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
func canConnect(connectionState: ConnectionState) -> Bool {
var result = false
switch connectionState {
case .Connected(let port):
if port == 3000 {
result = true
}
default:
result = false
}
return result
}
let state = ConnectionState.Connected(3000)
if canConnect(state) {
// …
}
|
Функция canConnect возвращает значение true только если экземпляр ConnectionState переданный в функцию, равен .Connected а его соответствующее значение равно Int равному 3000 . Обратите внимание, что соответствующее значение члена Connected доступно в операторе switch как константа с именем port , которую мы затем можем использовать в соответствующем case .
3. Связанные ценности
Другой неотъемлемой чертой перечислений Swift являются связанные значения. Каждый член перечисления может иметь ассоциированное значение. Связанные ценности очень гибки. Например, связанные значения разных членов одного и того же перечисления не обязательно должны быть одного типа. Посмотрите на следующий пример, чтобы лучше понять концепцию связанных значений.
|
1
2
3
4
5
6
|
enum ConnectionState {
case Unknown
case Disconnected
case Connecting(Int, Double)
case Connected(Int)
}
|
Unknown и Disconnected члены не имеют связанного значения. Элемент Connecting имеет ассоциированное значение типа (Int, Double) , указывающее номер порта и интервал ожидания соединения. У элемента Connected есть связанное значение типа Int , указывающее номер порта.
Важно понимать, что связанное значение связано или связано с членом перечисления. Значение участника остается неизменным. В следующем примере показано, как создать экземпляр ConnectionState со связанным значением.
|
1
|
var connectionState = ConnectionState.Connecting(3000, 30.0)
|
4. Методы и типы значений
методы
Перечисления довольно мощные в Swift. Перечисления могут даже определять методы, такие как инициализатор, для выбора значения элемента по умолчанию, если ни один не был указан.
|
01
02
03
04
05
06
07
08
09
10
11
12
|
enum ConnectionState {
case Unknown
case Disconnected
case Connecting(Int, Double)
case Connected(Int)
init () {
self = .Unknown
}
}
var connectionState = ConnectionState() // .Unknown
|
В этом примере мы инициализируем экземпляр перечисления ConnectionState без явного указания его значения. Однако в инициализаторе перечисления мы установили для экземпляра значение Unknown . В результате переменная connectionState равна ConnectionState.Unknown .
Типы значений
Как и структуры, перечисления являются типами значений, что означает, что перечисление передается не по ссылке, как экземпляры классов, а по значению. Следующий пример иллюстрирует это.
|
1
2
3
4
5
6
7
|
var connectionState1 = ConnectionState()
var connectionState2 = connectionState1
connectionState1 = .Connected(1000)
println(connectionState1) // .Connected(1000)
println(connectionState2) // .Unknown
|
Несмотря на то, что мы присваиваем connectionState1 для connectionState2 , значения connectionState1 и connectionState2 отличаются в конце примера.
Когда connectionState1 назначается для connectionState2 , Swift создает копию connectionState1 и назначает его для connectionState2 . Другими словами, connectionState1 и connectionState2 ссылаются на два разных экземпляра ConnectionState .
Вывод
Перечисления в Swift являются невероятно мощными по сравнению, например, с перечислениями в C. Один из самых мощных аспектов перечислений заключается в том, что они являются первоклассными типами в Swift. Безопасность типов является ключевым аспектом языка Swift, и перечисления идеально вписываются в это мышление.