Las enumeraciones en Swift comprenden una de sus características más poderosas. El propósito de una enumeración es agrupar semánticamente un grupo de opciones.
Se declaran usando la palabra reservada enum
:
enum UserType {
case admin
case editor
case author
case reader
}
El listado de código anterior define una enumeración llamada UserType
que tiene como opciones .admin
, .editor
, .author
y .reader
. En este contexto, nuestro programa ahora cuenta con un nuevo tipo de dato UserType
y podemos usarlo al igual que usaríamos cualquier Int
ó String
.
// Una estructura User que tiene una propiedad type de tipo UserType
struct User {
let type: UserType = .admin
}
func userDidLogin(user: User) {
switch user.type {
case .admin:
// Mostrar el panel de administrador
case .editor:
// Mostrar el panel de edición
case .author:
// Mostrar el panel de autores
case .reader:
// Mostrar lista de lectura
}
}
En el ejemplo anterior, hay una estructura User
con una propiedad type: UserType
, la cual sirve como referencia para determinar si el usuario en cuestión puede o no acceder al panel de administrador.
Este tipo de aplicaciones es muy común cuando se trata de enumeraciones en Swift: una lista de posibles valores, a partir de los cuales se van a tomar decisiones.
Con datos de respaldo
Cuando UserType
fue declarado anteriormente, no se le asignó ningún tipo de dato a cada uno de los miembros de la enumeración.
Las enumeraciones también se pueden crear a partir de datos brutos, o raw values. Los miembros de una enumeración que tiene datos de respaldo pueden ser creados a partir de dichos datos.
Ejemplo:
enum PodiumPlace: Int {
case first = 1
case second = 2
case third = 3
}
let firstPlace: PodiumPlace = .first // #=> firstPlace.rawValue == 1
let secondPlace = PodiumPlace(rawValue: 2) // #=> secondPlace.rawValue == 2
Usando el constructor rawValue:
podemos pasar un argumento del tipo de dato que respalda a la enumeración. Si el dato que pasamos al constructor es igual a uno de los declarados en la enumeración, se generará una instancia de la enumeración.
Algunos puntos a considerar sobre las enumeraciones con datos de respaldo:
- Todos los miembros de la misma deben de tener el mismo tipo de dato de respaldo. No se puede declarar una enumeración
enum Foo: Int
y asignarle cadenas de texto a sus miembros. - El constructor
rawValue
retornaránil
si el valor proporcionado no corresponde a ningún miembro de la enumeración.
Valores de respaldo implícitamente declarados
Cuando se quiere trabajar con enumeraciones con datos de respaldo que siguen una secuencia lógica, como el ejemplo anterior (1, 2, 3), se puede declarar solamente el valor que inicia la secuencia, y Swift inferirá el resto de los valores:
enum PodiumPlace: Int {
case first = 1
case second
case third
}
print(PodiumPlace.third.rawValue) // #=> 3
De la misma forma, cuando se requiere que el tipo de dato de respaldo sea String
, siempre y cuando los valores brutos de cada miembro sean iguales a los miembros de la enumeración, se puede omitir la declaración explícita:
enum UserType: String{
case admin
case reader
}
print(UserType.admin.rawValue) // #=> "admin"
let reader = UserType(rawValue: "reader")
let superAdmin = UserType(rawValue: "super_admin")
print(reader.rawValue) // #=> "reader"
print(superAdmin) // #=> nil
enums
con tipos de datos asociados
Las enumeraciones, además poder tener tipos de dato de respalo, pueden, por así decirlo, transportar datos.
enum Result {
case error(Int, String)
case success(AnyObject)
}
En el listado de código anterior definimos una enumeración con dos cases que pueden transportar datos: .error
que tiene asociados un Int
y un String
, y .success
, que puede transportar cualquier objeto.
let error = Result.error(404, "Not Found")
switch error {
case .error(let code, let description):
// Mostrar el error al usuario, y/ó realizar operaciones necesarias
case .success(let value):
// La operación no tuvo errores, value contiene el resultado esperado
}
El listado anterior muestra cómo podemos trabajar cuando tenemos enumeraciones con datos asociados.