SALE ENDS TODAY: Save 50% on all Swift books and bundles! >>

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.

SPONSORED Instabug helps you identify and resolve severe crashes quickly. You can retrace in-app events and know exactly which line of code caused the crash along with environment details, network logs, repro steps, and the session profiler. Ask more questions or keep users up-to-date with in-app replies straight from your dashboard. Instabug takes data privacy seriously, so no one sees your data but you! See more detailed features comparison and try Instabug's crash reporting SDK for free.

Save 50% on all books and bundles

The biggest ever Hacking with Swift sale is now on, letting you save 50% on all books and bundles. Learn something new with Swift and enjoy great savings while the sale lasts!

Click here to save 50% in our Black Friday sale!

BUY OUR BOOKS
Buy Pro Swift 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 (Vapor Edition) 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 Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!