UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Enumeraciones

Las enumeraciones – usualmente llamadas solamente "enum" y pronunciadas "inum" en idioma inglés - son una manera de definir tu propio tipo de valor en Swift. En algunos lenguajes de programación son pequeñas cosas simples, pero Swift les añade una gran cantidad de poder si quieres ir más allá de lo básico.

Comencemos con un simple ejemplo que habíamos visto anteriormente:

func getHaterStatus(weather: String) -> String? {
    if weather == "sunny" {
        return nil
    } else {
        return "Hate"
    }
}

Esta función acepta una cadena de caracteres que define el tiempo actual. El problema es que una cadena de caracteres es una pobre elección para este tipo de dato – ¿es "rain", "rainy" o "raining"? ¿O quizás "showering", "drizzly" o "stormy"? Peor aún, ¿que ocurriría si una persona escribe "Rain" con una R mayúscula y otro escribe "Ran" porque no estaba prestando atención a lo que escribían?

Las enumeraciones solucionan este problema permitiéndote definir un nuevo tipo de dato, para entonces definir los posibles valores que puede contener. Por ejemplo, podemos decir que existen cinco tipos de tiempo: sun, cloud, rain, wind and snow. Si con esto construimos un enum, significa que Swift solo aceptará estos cincos valores – cualquier otro valor lanzaría un error. Además, tras bastidores, los enums son usualmente solo simples números, con los cuales los ordenadores trabajan mucho más rápido que con una cadena de caracteres.

Llevemos lo visto a código:

enum WeatherType {
    case sun, cloud, rain, wind, snow
}

func getHaterStatus(weather: WeatherType) -> String? {
    if weather == WeatherType.sun {
        return nil
    } else {
        return "Hate"
    }
}

getHaterStatus(weather: WeatherType.cloud)

Echa un vistazo a las tres primeras líneas: la línea 1 le da un nombre a nuestro tipo, WeatherType. Esto lo utilizarás en lugar de String o Int en tu código. La línea 2 define los cinco posibles casos que nuestro enum puede tomar, como ya había aclarado anteriormente. La convención indica que estos comienzan con minúscula, de ahí “sun”, “cloud”, etc. Finalmente la línea 3 es una llave de cierre, finalizando el enum.

Veamos ahora como es utilizado: modifiqué el método getHaterStatus() para que acepte un valor de tipo WeatherType. Reescribí la sentencia condicional para que compare contra WeatherType.sun, el cual es nuestro valor. Recuerda, entre bastidores esta comparación es solo contra un valor numérico, lo cual es increíblemente raápido.

Ahora regresa y lee ese código nuevamente, porque estoy a punto de reescribirlo con dos cambios que son importantes. ¿Todo listo?

enum WeatherType {
    case sun
    case cloud
    case rain
    case wind
    case snow
}

func getHaterStatus(weather: WeatherType) -> String? {
    if weather == .sun {
        return nil
    } else {
        return "Hate"
    }
}

getHaterStatus(weather: .cloud)

Hay dos diferencias en el código anterior. Primero, cada uno de los tipos de tiempo están ahora ubicados en su propia línea. Esto puede paracer un pequeño cambio, y de hecho lo es en este ejemplo, pero será importante muy pronto. El segundo cambio es que escribí if weather == .sun – No necesité escribir claramente que quería decir WeatherType.sun porque Swift conoce que estoy comparando contra una variable de tipo WeatherType, de manera que utiliza la inferencia de tipo.

Los Enums son especialmente útiles dentro los bloquesswitch/case, en particular porque Swift conoce todos los valores que tu enum puede tener de manera que puede asegurar que cubras todos los casos. Por ejemplo, podemos intentar reescribir el método getHaterStatus() a esto:

func getHaterStatus(weather: WeatherType) -> String? {
    switch weather {
    case .sun:
        return nil
    case .cloud, .wind:
        return "dislike"
    case .rain:
        return "hate"
    }
}

Sí, me doy cuenta que "haters gonna dislike" es difícilmente una letra grandiosa, pero de todos modos es académica porque este código no se ejecutará: no maneja el caso .snow, y Swift quiere que todos los casos sean cubiertos. Tienes que tener un caso para él o añadir un caso por defecto.

Enums con valores adicionales

Una de las caracterícas más poderosas de Swift es que las enumeraciones pueden tener valores adjuntos definidos por ti. Para extender un poco más nuestro cada vez más dudoso ejemplo, voy a añadir un valor al caso .wind de modo que podamos decir qué tan rápido es el viento. Modifica tu código a esto:

enum WeatherType {
    case sun
    case cloud
    case rain
    case wind(speed: Int)
    case snow
}

Cómo puedes ver, los otros casos no necesitan un valor de velocidad - solamente lo puse en wind. Ahora la real magia: Swift nos permite añadir condiciones extra al bloque switch/case de manera que un caso coincidirá solamente si esas condiciones son verdaderas. Esto hace uso de la palabra reservada let para acceder al valor dentro de un caso, luego la palabra reservada where para la coincidencia de patrones.

Aquí está la nueva función:

func getHaterStatus(weather: WeatherType) -> String? {
    switch weather {
    case .sun:
        return nil
    case .wind(let speed) where speed < 10:
        return "meh"
    case .cloud, .wind:
        return "dislike"
    case .rain, .snow:
        return "hate"
    }
}

getHaterStatus(weather: WeatherType.wind(speed: 5))

Puedes ver que .wind aparece doble, pero la primera vez es verdadero solamente si el viento es menor de 10 kilómetros por hora. Si el viento es 10 o más, no coincidirá. La clave es que utilizas let para conseguir el valor dentro del enum (por ejemplo para declarar una constante que puedas referenciar) y luego utilizar una condición where a validar.

Swift evalúa los bloques switch/case de arriba a abajo, y se detiene tan pronto encuentra una coincidencia. Esto significa que si case .cloud, .wind: aparece antes que case .wind(let speed) where speed < 10: entonces se ejecutaría primero – y el resultado cambia.

Entonces, piensa cuidadosamente cómo organizas tus casos!

Nota: Las variables opcionales de Swift están implementadas utilizando enums con valores asociados. Hay dos casos: none, y some, con some teniendo cualquier valor que esté dentro del opcional.

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

BUY OUR BOOKS
Buy Pro Swift Buy Pro SwiftUI Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Beyond Code

Was this page useful? Let us know!

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.