Перечисления являются общим шаблоном проектирования во многих языках программирования. Хотя вы, возможно, знакомы с перечислениями в 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, и перечисления идеально вписываются в это мышление.