() translation by (you can also view the original English article)
En
el artículo anterior, aprendió sobre variables, constantes y algunos de
los tipos de datos comunes, como enteros, flotantes y cadenas. En este
artículo, nos acercamos a las colecciones. La biblioteca estándar de
Swift define dos tipos de colecciones, matrices y diccionarios. Comencemos con las matrices.
1. Arrays
Si está familiarizado con Objective-C, JavaScript o PHP, entonces no le resultará difícil entender el concepto de matrices. Una matriz es una colección de valores ordenada y de índice cero. Sin embargo, hay algunas diferencias importantes.
Tipos
La primera diferencia importante con las matrices en Objective-C es que los valores almacenados en una matriz son siempre del mismo tipo. Al principio, esto puede parecer una limitación importante, pero en realidad no lo es. De hecho, esta limitación tiene una ventaja importante. Sabemos exactamente qué tipo recuperamos cuando le preguntamos a la matriz por uno de sus valores.
Otra diferencia clave con las matrices Objective-C es el tipo de valores que una matriz puede almacenar. En Objective-C, una matriz solo puede almacenar valores de un tipo de clase. Swift no tiene esta limitación. Una matriz en Swift puede almacenar cadenas, enteros, flotantes, así como instancias de clase. Cómo funciona esto y por qué esto es posible en Swift quedará claro más adelante en esta serie cuando cubrimos clases y estructuras.
Declaración
Si bien la creación de una matriz se puede hacer de varias maneras, debe tener en cuenta que Swift necesita saber qué tipo de valores planea almacenar en la matriz. Cree un nuevo parque infantil en Xcode como lo hicimos en el artículo anterior y agregue las siguientes líneas.
1 |
var array1: Array<String> |
2 |
var array2: [String] |
3 |
var array3 = ["Apple", "Pear", "Orange"] |
La segunda línea es la abreviatura de la primera línea. Los
corchetes que envuelven la palabra clave String
indican a Swift que
estamos declarando una matriz que solo puede contener objetos
String
.
Puede
leer la primera línea de código como "Declaramos una variable llamada
array1
de tipo Array
que solo puede contener objetos String
". Tenga en
cuenta que he puesto en cursiva tipo ya que eso es lo que significa el corchete.
La tercera línea nos muestra cómo inicializar una matriz usando
una matriz literal. Los literales de matriz se ven muy similares a los
literales de matriz en Objective-C. La principal diferencia es la
ausencia del símbolo @
que precede a los corchetes y los literales de
cadena.
También hay una manera elegante de inicializar una matriz con una cantidad predefinida de valores predeterminados. La sintaxis puede ser confusa al principio, pero tómese un momento para dejar que se hunda.
1 |
var a = [String](count: 5, repeatedValue: "Test") |
La matriz
resultante contiene cinco cadenas, siendo cada cadena igual a "Test"
. Para
comprender mejor la inicialización anterior, eche un vistazo a las dos
líneas de código siguientes en las que inicializamos una matriz vacía de
cadenas.
1 |
var b = Array<String>() |
2 |
var c = [String]() |
No te preocupes si todavía estás confundido. Exploraremos la sintaxis con más detalle una vez que comencemos a manejar clases y funciones. En este artículo, solo nos centramos en las colecciones.
Mutabilidad
Un aspecto de Swift que
pronto apreciará es cómo declarar colecciones mutables. El fragmento de
código anterior, por ejemplo, declara tres matrices mutables. Una
matriz mutable se define utilizando la palabra clave var
. Es así de
simple. Si no desea que una matriz sea mutable, utilice la palabra clave
let
en su lugar. Swift
tiene como objetivo ser intuitivo y fácil de usar, y la implementación
de mutabilidad de Swift es un ejemplo perfecto de este
objetivo.
Obteniendo y Configurando Valores
Para acceder a los valores
almacenados en una matriz, utilizamos la misma sintaxis de subíndices
que en Objective-C. En el siguiente ejemplo, le preguntamos a array3
por
su segundo elemento, la cadena "pear"
.
1 |
array3[1] |
Reemplazar el valor
almacenado en el índice 1
es tan simple como asignar un nuevo valor
usando la misma sintaxis de subíndice. En el siguiente ejemplo,
reemplazamos "pear"
en el índice 1
con"peach"
.
1 |
array3[1] = "Peach" |
Esto solo es posible porque la matriz es mutable, es decir,
usamos la palabra clave var
para declarar la matriz. Mutar una matriz
constante no es posible. Existen técnicas más avanzadas para manipular
el contenido de una matriz, pero el concepto subyacente es el
mismo.
Combinar dos matrices es tan simple como sumarlas. En el siguiente
ejemplo, declaramos y fusionamos dos matrices inmutables. Tenga en
cuenta que la matriz resultante, c
, no necesita ser mutable para que
esto funcione.
1 |
let a = [1, 2, 3] |
2 |
let b = [4, 5, 6] |
3 |
|
4 |
let c = a + b |
Sin
embargo, es clave que los valores almacenados en a
y b
sean del mismo
tipo. La razón debería ser obvia por ahora. Los valores almacenados en
una matriz deben ser del mismo tipo. El siguiente ejemplo dará como
resultado un error.
1 |
let a = [1, 2, 3] |
2 |
let b = [1.5, 5.2, 6.3] |
3 |
|
4 |
let c = a + b |
Para agregar una matriz a una matriz mutable, usamos el operador
+=
. Tenga en cuenta que el operando de la derecha es una matriz. Esta
operación no funcionaría si eliminamos los corchetes que rodean al 4
.
1 |
var a = [1, 2, 3] |
2 |
a += [4] |
Operaciones
Las matrices son objetos sobre los que puede realizar una amplia gama de operaciones. Las matrices exponen una cantidad de funciones o métodos. Para invocar
un método en un objeto, usa la notación de puntos. Agregue la siguiente
línea a su área de juegos para agregar un elemento a
array3
.
1 |
array3.append("Cherry") |
Veamos cuántos elementos contiene array3
invocando su método count
. Esto produce 4
en el panel de
resultados a la derecha.
1 |
array3.count |
También
es posible insertar un elemento en un índice específico invocando el
método insert
de la matriz como se muestra a continuación. El
método insert
acepta más de un parámetro y puede parecer un poco
extraño al principio.
1 |
array3.insert("Prune", atIndex: 2) |
Al igual que
Objective-C, Swift admite parámetros con nombre para mejorar la
legibilidad. El
resultado es que el código es más fácil de leer y comprender, y las
funciones o métodos no necesitan mucha explicación en términos de lo que
hacen. Está claro, por ejemplo, que el método insert
inserta un
elemento en el índice 2
.
Si bien Swift es más conciso y menos detallado que Objective-C, sí admite parámetros con nombre. Si vienes de PHP, Ruby o JavaScript, esto es algo que te tomará un tiempo acostumbrarse.
Métodos de conveniencia
Lo
que realmente disfruto de Swift son las propiedades y los métodos de
conveniencia similares a Ruby de la biblioteca estándar de Swift. Una
matriz, por ejemplo, tiene una propiedad isEmpty
que le dice si la
matriz contiene elementos. Esto no es más que una abreviatura para
verificar la propiedad count
de la matriz. El resultado, sin
embargo, es un código que es más conciso y fácil de
leer.
1 |
array3.isEmpty |
2. Diccionarios
Los diccionarios se comportan de forma muy similar a los diccionarios en Objective-C. Un diccionario almacena una colección desordenada de valores. Cada valor en el diccionario está asociado con una clave. En otras palabras, un diccionario almacena una cantidad de pares clave / valor.
Tipo
Al igual que con las matrices, las claves y los valores almacenados en un diccionario deben ser del mismo tipo. Esto significa que si le preguntas a un diccionario por el valor de una clave en particular, sabes qué tipo devolverá el diccionario.
Declaraciónes
Declarar un diccionario es similar a declarar una matriz. La diferencia es que debe especificar el tipo de claves y valores. El siguiente ejemplo muestra tres formas de declarar un diccionario.
1 |
var dictionary1: Dictionary<String, Int> |
2 |
var dictionary2: [String: Int] |
3 |
var dictionary3 = ["Apple": 3, "Pear": 8, "Orange": 11] |
La segunda línea es la abreviatura de la primera línea. Las claves de estos diccionarios deben ser de tipo String
, mientras que
se espera que los valores sean del tipo Int
. La palabra clave var
indica
que los diccionarios son mutables.
Puede
leer la primera línea de código como "Declaramos una variable llamada
dictionary1
de tipo Dictionary
que solo puede contener claves de tipo
String
y valores de tipo Int
".
La tercera línea ilustra cómo podemos
inicializar un diccionario usando un literal de diccionario. Esto
es similar a la sintaxis que usamos en Objective-C, pero tenga en
cuenta que las llaves se reemplazan por corchetes y el literal no está
precedido de un símbolo @
.
Obteniendo y Configurando Valores
El acceso a los valores es similar al acceso a los valores de una matriz. La única diferencia es que usa la clave en lugar del índice del valor al que necesita acceder. El siguiente ejemplo lo ilustra.
1 |
let value = dictionary3["Apple"] |
2 |
println(value) |
Notará que Xcode nos dice que el
valor del value
no es 3
, sino Optional(3)
. ¿Qué significa esto? Swift
usa opcionales para ajustar valores que pueden ser una de dos cosas, un
valor o nulll
. No se preocupe por los opcionales en este punto. Nos
centraremos en los opcionales en el siguiente artículo de esta serie. Permítanme decirles que los opcionales son otro concepto clave del
lenguaje de programación Swift.
Es
interesante señalar que la sintaxis para acceder a un valor de un
diccionario es idéntica a la de las matrices si las claves del
diccionario son de tipo Int
. Eche un vistazo al siguiente ejemplo para
ver a qué me refiero.
1 |
var dictionary4 = [0: "Apple", 1: "Pear", 2: "Orange"] |
2 |
let fruit = dictionary4[0] |
Operaciones
Al
igual que con las matrices, la biblioteca estándar Swift define una
amplia gama de operaciones que puede realizar en diccionarios. Un
diccionario devuelve su número de pares clave / valor al invocar count
en él. La eliminación de un par de clave / valor es fácil e intuitiva,
como lo ilustra el siguiente ejemplo. Por supuesto, esto solo es posible
si el diccionario es mutable.
1 |
dictionary4.removeValueForKey(0) |
Cuando empiezas a aprender Swift, ocasionalmente te toparás con fragmentos de código que parecen extraños o confusos. Eche un vistazo a la siguiente línea en la que primero declaramos un diccionario y luego eliminamos sus pares clave / valor.
1 |
var dictionary = [String: Int]() |
2 |
|
3 |
dictionary["Oranges"] = 2 |
4 |
dictionary["Apples"] = 10 |
5 |
dictionary["Pears"] = 5 |
6 |
|
7 |
dictionary = [:] |
Tienes que admitir que la última línea
parece un poco extraña. Como
Swift conoce los tipos de claves y valores que se pueden almacenar en
dictionary
, vaciar el diccionario es tan simple como asignarle un
diccionario vacío.
No es necesario especificar los tipos para las claves y los valores en este caso, porque ya lo hicimos cuando declaramos el diccionario en la primera línea. Esto señala otro detalle importante, es decir, el tipo de valores que puede almacenar en matrices y diccionarios no puede cambiar una vez que se declara la colección.
3. Tuples
Te van a encantar las tuplas. Si bien las tuplas no son colecciones, también agrupan múltiples valores. De forma similar a las matrices y los diccionarios, las tuplas pueden contener valores de cualquier tipo. La diferencia clave, sin embargo, es que los valores almacenados en una tupla no necesitan ser del mismo tipo. Veamos un ejemplo para explicar esto con más detalle.
1 |
var currency = ("EUR", 0.81) |
2 |
var time = (NSDate(), "This is my message.") |
3 |
var email = ("Bart Jacobs", "bart@example.com") |
El primer ejemplo declara una tupla llamada
currency
que es de tipo (String, Int)
. La segunda tupla, tiempo, contiene
una instancia NSDate
y una cadena literal. Los
valores almacenados en el email
son de tipo String
, lo que
significa que el email
es del tipo (String, String)
.
Acceso a valores
Índices
Para acceder a un valor almacenado en una tupla, utiliza el índice que corresponde con el valor que le interesa.
1 |
var rate = currency.1 |
2 |
var message = time.1 |
3 |
var name = email.0 |
Xcode nos muestra los índices de cada valor almacenado en una tupla en el panel de resultados del patio de recreo de la derecha.



Nombres
Para mejorar la legibilidad, puede nombrar los valores almacenados en una tupla. El resultado es que puede acceder a los valores de la tupla a través de sus nombres en lugar de sus índices. Declarar una tupla es ligeramente diferente en ese caso.
1 |
var currency = (name: "EUR", rate: 0.81) |
2 |
let currencyName = currency.name |
3 |
let currencyRate = currency.rate |
Descomposición
Hay una segunda forma más elegante de
trabajar con los valores almacenados en una tupla. Eche un vistazo al
siguiente ejemplo en el que descomponemos el contenido de currency
.
1 |
let (currencyName, currencyRate) = currency |
El valor currency
en el índice
0
se almacena en currencyName
y el valor en el índice 1
se almacena en
currencyRate
. No
es necesario especificar el tipo para currencyName
y currencyRate
ya
que Swift infiere el tipo de los valores almacenados en currency
. En
otras palabras, currencyName
es de tipo String
y currencyRate
es de tipo
Float
.
Si solo está interesado en valores específicos de una tupla, puede usar un guión bajo para indicarle a Swift qué valores no le interesan.
1 |
let (currencyName, _) = currency |
Aprenda más en nuestro curso de programación Swift
Lleve su educación Swift al próximo nivel y aprenda sobre todo, hasta la Programación Orientada a Objetos en nuestro curso completo sobre desarrollo de Swift.
Conclusión
Las matrices y los diccionarios son componentes fundamentales de casi todos los lenguajes de programación y Swift no es diferente. Si bien las colecciones se comportan de forma diferente en Swift, no lleva mucho tiempo familiarizarse con los tipos de colección de Swift si ha trabajado con matrices y diccionarios en otros lenguajes de programación. En el siguiente tutorial, exploramos opcionales y controlamos el flujo.