Una estructura es un tipo de dato complejo que encapsula datos (variables y constantes, también llamados propiedades, miembros o atributos) y comportamiento (métodos). Las instancias de una estructura son únicas.
Atributos
Los atributos de una estructura se pueden definir de forma explícita (i.e. var nombre: Tipo = valor) o dejar que Swift infiera el tipo (i.e. var nombre = valor).
struct Person {
var name: String = "David"
var age: Int = 10
}
var instance1 = Person()
La instancia es creada por el inicialiador de Person (i.e. Person() o Person.init()) y asignada a la variable instance1.
Para acceder a un atributo se usa la notación punto, como en instancia.propiedad, donde instancia es el nombre de la variable que contiene la instancia de la estructura y propiedad es el nombre de la propiedad que se quiere acceder.
struct Person {
var name = "David"
var age = 10
}
var instance1 = Person()
instance1.age = 11
print("Persona: \(instance1.name)")
Para modificar los valores de una estructura se requiere que los atributos de la estructura sean variables (e.g. var name, var age). Además de eso, la instancia de la estructura también debe ser variable (e.g. var instance1) porque al modificar una variable, en realidad el sistema crea una nueva estructura con los nuevos valores, que luego reemplaza por la instancia inicial.
Métodos
Una función definida dentro de una estructura se llama método.
La sintaxis para invocar un método es: instancia.metodo() donde instancia es el nombre de la variable que contiene la instancia de la estructura y metodo() es el nombre del método que se quiere invocar sobre esa instancia. Por ejemplo:
struct Person {
var name = "David"
var age = 10
func saludar() {
print("Hola, soy \(name) y tengo \(age) años")
}
}
var instance1 = Person()
instance1.age = 11
instance1.saludar()
Gracias a los métodos, no es necesario conocer los detalles del comportamiento definido en él, ni tampoco es necesario extraer la información de los atributos de la estructura. Simplemente se le pasan los argumentos que hagan falta y se deja a la instancia hacer el trabajo.
Para cambiar los valores de una estructura con un método, se lo debe modificar con la palabra clave mutating. Por ejemplo:
struct Person {
var name = "David"
var age = 10
func saludar() {
print("Hola, soy \(name) y tengo \(age) años")
}
mutating func crecer() {
age += 1
}
}
var instance1 = Person()
instance1.age = 11
instance1.crecer()
instance1.saludar() // Hola, soy David y tengo 12 años
Propiedades computadas
Las variables almacenadas almacenan un valor en memoria. En cambio, las variables computadas no almacenan nada sino que ejecutan alguna operaciones sobre las variables computadas leyendo o modificando sus valores.
Para modificar y extraer el valor de una variable computada se usan los métodos set y get, respectivamente. Solo get es obligatorio.
struct Person {
var name = "David"
var age = 10
var nextAge {
get {
age + 1
}
}
}
let person1 = Person()
person1.nextAge // 11
Las variables computadas son como métodos porque calculan su valor cada vez que se lee la propiedad.
Propiedad computada de solo-lectura
Cuando una propiedad computada solo tiene el getter (i.e. get), se dice que es de solo lectura, y podemos omitir la firma del método get.
struct Person {
var name = "David"
var age = 10
var nextAge {
age + 1
}
}
let person1 = Person()
person1.nextAge // 11
Propiedad computada de lectura y escritura
Al agregar el setter, set, se puede modificar el estado de la estructura al cambiar el valor de la variable computada. El nuevo valor de la variable computada se llama newValue. En caso de necesitar usar un nombre diferente de newValue se puede especificar entre paréntesis.
struct Person {
var name = "David"
var age = 10
var nextAge {
get {
age + 1
}
set {
age = newValue - 1
}
}
var previousAge {
get { age - 1 }
set(previous) {
age = previous + 1
}
}
}
let person1 = Person()
person1.nextAge // 11
Property-observers
Los "Property-observers" informan del cambio de una propiedad de una estructura. Estos observadores son métodos especiales, similar a get y set que se pueden incluir en una propiedad para ejecutar código antes (willSet) y después (didSet) de que haya cambiado.
Dentro de willSet hay un parámetro llamado newValue con el valor que va a ser asignado a la propiedad. Por su parte, en didSet, el parámetro oldValue es el valor de la propiedad antes de ser modificado.
struct Person {
var name = "David"
var age = 10 {
willSet {
print("La nueva edad será: \(newValue)")
}
didSet {
print("La edad era: \(oldValue) y ahora es: \(age)")
}
}
}
let person1 = Person()
person1.age = 11
// La nueva edad será: 11
// La edad era: 10 y ahora es: 11
Tipos de datos primitivos como estructuras
Todos los tipos de datos primitivos de Swift están definidos como estructuras.
Cada vez que asignamos un nuevo valor a una variable de tipo primitivo, estamos asignando una estructura que contiene dicho valor.
Por ejemplo, la sintaxis variable: Int = value se traduce en variable = Int(value).
var myInt = Int(25)
var myDouble = Double(4.99)
Las estructuras definidas para los tipos de datos primitivos también tienen sus propias propiedades y métodos estáticas. Por ejemplo, estas son algunas de las propiedades y métodos más usados:
-
Int.min: Retorna el valor mínimo que puede manejar el tipo de dato. -
Int.max: Retorna el valor máximo que puede manejar el tipo de dato. -
Int.random(in: Range): Retorna un número aleatorio, entre un rango. -
.negate(): Invierte el signo. -
.isMultiple(of: Int): Retornatruesi el valor es múltiplo del argumento. -
Double.pi: Constante pi. -
Double.inifinity: Retorna un valor muy grande. -
Double.random(in: Range): Retorna un valor aleatorio. -
.squareRoot: Raíz cuadrada -
.remainder(dividingBy: Double): Residuo de la operación -
.rounded(FloatingPointRoundingRule): Redondear un número.

