Las estructuras y las clases son dos de los bloques de construcción principales de la programación en Swift. Ambas son formas de agrupar datos y funciones relacionados en unidades de funcionalidad autocontenidas. Y cuando defines una estructura o una clase, estás definiendo un nuevo tipo que se usará en Swift, igual que usaste los tipos con los que ya has trabajado, como Int y String.
Hay muchas similitudes entre las estructuras y las clases en Swift. Entre otras similitudes, ambas pueden almacenar valores en propiedades y proporcionar funcionalidad mediante el uso de métodos.
Cada una proporciona funcionalidad adicional, que queda fuera del alcance de este ejercicio.
Tanto las estructuras como las clases se definen de forma similar. Comienzan con la palabra clave adecuada seguida del nombre del tipo que se está definiendo; después sigue el cuerpo de la estructura o clase, colocado entre llaves.
El cuerpo puede constar de propiedades almacenadas, que se definen y se comportan igual que las constantes o variables normales.
struct CharacterStats {
var health = 0.0
var speed = 0
var strength = 0
}
class GameCharacter {
var stats = CharacterStats()
var characterClass: String?
var name: String?
var active = false
let id = makeRandomID()
}
Como se ha indicado antes, definir una estructura o una clase es solo definir un nuevo tipo. Es solo el plano de cómo serán los valores de ese tipo, pero no crea ningún valor de ese tipo con el que puedas trabajar.
Para crear una instancia de ese tipo, debes escribir el nombre del tipo seguido de un par de paréntesis.
let someStats = CharacterStats()
let someCharacter = GameCharacter()
Esto creará valores de estos tipos, donde las propiedades se rellenan con los valores predeterminados proporcionados en la definición. Ten en cuenta que, en casos opcionales como la propiedad name de GameCharacter, a menos que se proporcione un valor, la propiedad será nil de forma predeterminada, igual que al definir tipos opcionales normales en los que no se proporciona un valor de inmediato.
Con las estructuras, Swift proporciona automáticamente algo llamado inicializador por miembros, donde los valores para las propiedades de la estructura se pueden proporcionar dentro de los paréntesis, lo que anulará los valores predeterminados de la definición.
let differentStats = CharacterStats(health: 100.0, speed: 6, strength: 18)
Se puede acceder a las propiedades de estructuras y clases mediante la notación de punto, donde el nombre del valor va seguido de un punto (.) y el nombre de la propiedad. Si una propiedad de una estructura o clase tiene propiedades propias, esta notación de punto también puede usarse para acceder a esas propiedades anidadas.
Esta notación puede usarse tanto para obtener el valor de la propiedad como, cuando esté permitido, para cambiarlo.
someStats.health
// => 0
someCharacter.name
// => nil
someStats.health = 87.3
someStats.health
// => 87.3
someCharacter.name = "Luther"
someCharacter.name
// => "Luther"
someCharacter.id = "new id"
// Error: Cannot assign to property: 'id' is a 'let' constant
Al igual que las propiedades, que almacenan datos en tus estructuras y clases, también puedes definir métodos que almacenan funciones en tu estructura o clase.
Los métodos se definen igual que una función normal, solo que dentro del cuerpo de la estructura o clase. Ten en cuenta que, si una función cambia el valor de una propiedad en una estructura, debe ir precedida de la palabra clave mutating. Además, si un método puede cambiar una propiedad, esa propiedad debe definirse con var en lugar de let, igual que las variables normales.
struct CharacterStats {
var health = 0.0
var speed = 0
var strength = 0
mutating func takeHit(_ damage: Double) {
health = max(0.0, health - damage)
}
func canLift(_ weight: Int) -> Bool {
weight < strength * 100
}
}
class GameCharacter {
var stats = CharacterStats()
var characterClass: String?
var name: String?
var active = false
let id: String = makeRandomID()
func takesDamage(_ damage: Double) {
stats.takeHit(damage)
if stats.health <= 0 {
active = false
}
}
func sayName() -> String {
return "My name is \(name ?? "no one"), my class is \(characterClass ?? "undetermined")"
}
func lift(_ weight: Int) -> String {
if stats.canLift(weight) {
return "No problem!"
} else {
return "Ooof! No way."
}
}
}
Se puede llamar a estos métodos usando la notación de punto, igual que con las propiedades.
var myChar = GameCharacter()
myChar.stats = CharacterStats(health: 72.8, speed: 19, strength: 6)
myChar.active = true
myChar.lift(750)
// => "Ooof! No way."
myChar.takesDamage(80)
myChar.active
// => false
Cada instancia de una estructura o clase tiene una propiedad implícita llamada self, que se refiere a la instancia misma.
El uso más común de self es desambiguar entre una propiedad de instancia y un parámetro que comparte el mismo nombre:
struct Position {
var x = 0
mutating func move(x: Int) {
// Here, 'self.x' refers to the struct's property,
// while 'x' refers to the parameter passed to the method.
self.x = x
}
}
Los tipos de Swift también proporcionan una palabra clave Self con mayúscula, que se refiere al tipo de la instancia en lugar de a la instancia misma.
En este ejercicio vas a simular un sistema informático basado en ventanas. Crearás ventanas que se pueden mover y redimensionar, y que muestran su contenido. La siguiente imagen es representativa de los valores con los que vas a trabajar a continuación.
<--------------------- screenSize.width --------------------->
^ ╔════════════════════════════════════════════════════════════╗
| ║ ║
| ║ position.x,_ ║
| ║ position.y \ ║
| ║ \<----- size.width -----> ║
| ║ ^ *──────────────────────┐ ║
| ║ | │ title │ ║
| ║ | ├──────────────────────┤ ║
screenSize.height ║ | │ │ ║
| ║ size.height │ │ ║
| ║ | │ contents │ ║
| ║ | │ │ ║
| ║ | │ │ ║
| ║ v └──────────────────────┘ ║
| ║ ║
| ║ ║
v ╚════════════════════════════════════════════════════════════╝
Define una estructura llamada Size con dos propiedades de tipo Int, width y height, que almacenan el ancho y el alto actuales de la ventana, respectivamente.
El ancho y el alto iniciales deben ser 80 y 60, respectivamente.
Incluye un método resize(newWidth:newHeight:) que recibe nuevos parámetros de ancho y alto y cambia las propiedades para reflejar el nuevo tamaño.
let size1080x764 = Size(width: 1080, height: 764)
// Returns Size
var size1200x800 = size1080x764
// Returns Size
size1200x800.resize(newWidth: 1200, newHeight: 800)
size1200x800.height
// Returns 800
Define una estructura llamada Position con dos propiedades de tipo Int, x e y, que almacenan la posición horizontal y vertical actuales, respectivamente, de la esquina superior izquierda de la ventana.
Los valores iniciales de x e y deben ser 0. La posición (0, 0) es la esquina superior izquierda de la pantalla, con los valores de x que aumentan a medida que te mueves hacia la derecha y los valores de y que aumentan a medida que te mueves hacia abajo.
Incluye un método moveTo(newX:newY:) que recibe nuevos parámetros x e y y cambia las propiedades para reflejar la nueva posición.
var point = Position(x: 10, y: 20)
// Returns Position
point.moveTo(newX: 100, newY: -100)
point.y
// Returns -100
Define una clase ventana con las siguientes propiedades:
title : String, el valor inicial es "New Window"screenSize : Size, valor constante con width = 800 y height = 600size : Size, el valor inicial es el valor predeterminado de la estructura Size
position : Position, el valor inicial es el valor predeterminado de la estructura Position
contents : String?, el valor inicial es nil
También debes definir un inicializador vacío para la clase.
let window = Window()
window.title
// Returns "New Window"
resize(to:) : (Size) -> () - Este método recibe una estructura Size como entrada e intenta redimensionar la ventana al tamaño especificado. Sin embargo, el nuevo tamaño no puede superar ciertos límites.x = 400, y = 300 y se solicita un redimensionado a height = 400, width = 300, entonces la ventana se redimensionaría a height = 300, width = 300, ya que la pantalla no es lo suficientemente grande en la dirección y para satisfacer completamente la solicitud.move(to:) : (Position) -> () - Esto es similar a resize(to:), pero este método ajusta la posición de la ventana al valor solicitado, en lugar del tamaño. Al igual que con resize, la nueva posición no puede superar ciertos límites.x como para y.x = 250, y = 100 y se solicita un movimiento a x = 600, y = 200, entonces la ventana se movería a x = 550, y = 200, ya que la pantalla no es lo suficientemente grande en la dirección x para satisfacer completamente la solicitud.update(title:) : (String) -> () - Este método establece la propiedad title al valor del string que se pasó.update(text:) : (String?) -> () - Este método establece la propiedad contents al valor del string opcional que se pasó.display() : () -> String - Este método devuelve un string que describe el estado actual de la ventana. Por ejemplo, si la ventana tiene el title "My First Window" con posición: x = 10, y = 100; tamaño: width = 200, height = 150; y contents: "I 😍 my window", debería devolver el string: "My First Window\nPosition: (10, 100), Size: (200 x 150)\nI 😍 my window\n" - Si contents es nil, la última línea debería decir "[This window intentionally left blank]"El sistema de ventanas debería tener un inicializador para que la ventana se pueda crear con entradas personalizadas.
Crea otro inicializador para la clase Window.
El inicializador debe recibir los siguientes parámetros: title, contents, y dos parámetros opcionales size y position.
Los parámetros size y position deben tener como valores predeterminados los valores predeterminados de las estructuras Size y Position.
let window = Window(title: "My First Window", contents: "I 😍 my window")
window.display()
// Returns "My First Window\nPosition: (0, 0), Size: (80 x 60)\nI 😍 my window\n"
let window2 = Window(title: "My Second Window", contents: "I 😍 my window", size: Size(width: 200, height: 150), position: Position(x: 10, y: 100))
window2.display()
// Returns "My Second Window\nPosition: (10, 100), Size: (200 x 150)\nI 😍 my window\n"
Regístrate en Exercism para aprender y dominar Swift con 35 conceptos116 ejercicios y mentoría humana real, todo gratis.