Blog

Swift – Ejercicios propuestos (III)

Crea una clase llamada «Obstaculos» para crear los obstáculos de un videojuego. Debe tener un inicializador con los parámetros de anchura y altura de los obstáculos, que serán las propiedades de la clase. Deberá tener además un método «mostrar» que deberá listar esos datos por pantalla.

Crea un array de 10 obstáculos cuyas alturas y anchuras serán asignadas de forma aleatoria. La altura debe estar entre 40 y 100 píxeles y la anchura entre 90 y 120 píxeles y muestra todos los datos al final.

...

Crea una clase «Punto3D» para representar un punto en un espacio de 3 dimensiones que guarde las coordenadas x, y, z de dicho punto. Debe implementar los siguientes métodos:

  • Un inicializador para establecer los valores x, y, z.
  • Un método para mover dicho punto a otras coordenadas.
  • Un método para calcular la distancia entre el punto que represente el objeto, y el de otro objeto que reciba como parámetro. Para ello se deberá calcular la raiz cuadrada (se puede utilizar el método «squareRoot()» del tipo «Double») de la siguiente expresión: (xb – xa)2 + (yb – ya)2 + (zb – za)2
  • Un método «toString» que devolverá un «String» de la siguiente forma: (x, y, z)
  • Los get y los set para actualizar cada una de las coordenadas de forma individual.

Se deberá desarrollar además una clase de prueba que cree un array de 5 puntos, pidiendo los valores de las coordenadas y calcule y enseñe por pantalla la distancia desde el primer punto al resto.

...

Crear un array de libros utilizando el código de ejercicios anteriores. Se deberá crear un menú de consola con las opciones de añadir nuevo y libro y ver los datos de los libros existentes.

...

Crear un array de documentos utilizando el código de ejercicios anteriores. Se deberá crear un menú con las opciones de añadir nuevo documento o libro, pidiendo desde consola los datos correspondientes según se trate de un tipo u otro. También deberemos desarrollar la opción para ver los datos de los libros existentes.

...

Crear una clase «Puerta» para desarrollar un videojuego con un alto y un ancho y un método para mostrar dichos valores. Crear además una clase «Casa» para el mismo videojuego. Dicha clase contendrá 3 puertas, y tendrá otro método para mostrar por pantalla la palabra «Casa» y los datos de las tres puertas.

...

Crear una clase llamada «FotoAlbum» con un atributo que indique el número de páginas. Deberá tener un inicializador que reciba el número de páginas, y otro al que no se le pase ningún parámetro. Este último deberá crear el foto álbum con 16 páginas por defecto.

Se deberá desarrollar un método para mostrar por pantalla la siguiente expresión: «Soy un foto álbum de N páginas»

Además, se deberá desarrollar otra clase que herede de FotoAlbum y que se llame GranAlbum. Esta clase tendrá un inicializador sin parámetros que se utilice el de la clase base, generando un álbum de 64 páginas por defecto.

Por último, se deberá desarrollar un método para mostrar la siguiente expresión: «Soy un foto álbum de N páginas y soy grande», utilizando la función mostrar de la clase base para mostrar la primera parte del mensaje.

...

Crea una clase que se llame «Encriptador» con dos métodos estáticos para encriptar y desencriptar. Recibirán un «String» por parámetro devolviendo dicha cadena encriptada o desencriptada según el caso. La encriptación se llevará a cabo cambiando las vocales por los siguientes caracteres:

  • a -> |
  • e -> /
  • i -> @
  • o -> $
  • u -> &

Desarrollar una clase para probar dicho encriptador con varios ejemplos, teniendo en cuenta que se deben llamar a los métodos para encriptar o desencriptar sin crear un objeto, simplemente accediendo a la función de la clase con el «.» y pasando la cadena como parámetro de la función.

...

Swift – Ejercicios propuestos (II)

Desarrollar una clase para comprobar si un año es bisiesto:

class Bisiesto {
    var anyo:Int

    init(_ anyo: Int?) {
        self.anyo = Int(anyo ?? 0)
    }

    func esBisiesto() -> Bool {
        return (anyo % 4 == 0 && anyo % 100 != 0) || anyo % 400 == 0
    }
}

var anyo = Bisiesto(2300)

print(anyo.esBisiesto())

Crea una clase llamada Persona. Esta clase deberá tener un atributo «nombre», de tipo String. También deberá tener un método «setNombre», con un parámetro String, que permita cambiar el valor del nombre. Finalmente, también tendrá un método «saludar», que escribirá en pantalla «Hola, soy » seguido de su nombre. Crea también una clase llamada PruebaPersona. Esta clase deberá contener sólo la función main, que creará dos objetos de tipo Persona, les asignará un nombre a cada uno y les pedirá que saluden.

class Persona {
    var nombre:String = ""
    func setNombre(_ nombre:String) {
        self.nombre = nombre
    }
    func saludar() {
        print("Hola soy \(nombre)")
    }
}

class PruebaPersona {
    func main() {
        let persona1 = Persona()
        let persona2 = Persona()
        
        persona1.setNombre("Pepe")
        persona2.setNombre("Juan")
        
        persona1.saludar()
        persona2.saludar()
    }
}

var prueba = PruebaPersona()
prueba.main()

Para guardar información sobre libros, vamos a comenzar por crear una clase «Libro», que contendrá atributos «autor», «titulo», «ubicacion» (todos ellos Strings) y métodos get y set adecuados para leer su valor y cambiarlo (getAutor, getTitulo, …). Crea también una clase llamada «PruebaLibro». Esta clase deberá contener sólo la función «main», que cree un objeto de la clase «Libro», dé valores a sus tres atributos y luego los muestre.

...

Crea una clase «Coche», con atributos «marca» (texto), «modelo» (texto), «cilindrada» (número entero), potencia (número real) y métodos get y set adecuados para leer su valor y cambiarlo (getMarca, getModelo, …). Crea también una clase llamada «PruebaCoche». Esta clase deberá contener sólo la función «main», que cree un objeto de la clase «Coche», dé valores a sus tres atributos y luego los muestre.

...

Se debe crear una nueva clase «PersonaInglesa». Esta clase deberá heredar las características de la clase «Persona», y añadir un método «tomarTe», que escribirá en pantalla «Estoy tomando té». Crea también una clase llamada PruebaPersona2. Esta clase deberá contener sólo la función main, que creará dos objetos de tipo «Persona» y uno de tipo PersonaInglesa, les asignará un nombre, les pedirá que saluden y pedirá a la persona inglesa que tome té.

...

Crea una clase «Documento», de la que «Libro» heredará todos sus atributos y métodos. Ahora la clase «Libro» contendrá sólo un atributo «paginas», número entero, con sus correspondientes «getPaginas» y «setPaginas». Será la clase «Documento» la que tenga ahora las propiedades «autor», «titulo» y «ubicación».

...

Crea una clase «Vehiculo», de la que heredarán «Coche» y una nueva clase «Moto». La clase «Vehiculo» contendrá todos los atributos y métodos que antes estaban en «Coche», y tanto «Coche» como «Moto» heredarán de ella. Crea otra clase para probar el código.

...

Modificar la clase «PersonaInglesa» para que redefina el método «Saludar», para que escriba en pantalla «Hi, I am » seguido de su nombre; se creará una nueva clase «PersonaItaliana», que deberá heredar las características de la clase «Persona», pero se deberá redefinir el método «Saludar», para que escriba en pantalla «Ciao «; crea también una clase llamada PruebaPersona3, que deberá contener sólo la función «main» y creará un objeto de tipo «Persona», uno de tipo «PersonaInglesa», y uno de tipo «PersonaItaliana», les asignará un nombre, les pedirá que saluden y pedirá a la persona inglesa que tome té.

...

Amplia las clases del tipo persona, para que todas ellas contengan inicializadores. Los inicializadores de casi todas las clases estarán vacíos, excepto el de «PersonaInglesa», que prefijará su nombre a «John». Crea también un inicializador alternativo para esta clase que permita escoger cualquier otro nombre.

				

Ampliar la clase «Libro» para que tenga un inicializador que permita dar valores al autor, al título y la ubicación.

...

Mejora la clase «Coche» para añadir un atributo «cantidadDeRuedas» a la clase «Vehiculo», junto con sus get y set. El inicializador de la clase «Coche» le dará el valor 4 y el inicializador de la clase «Moto» le dará el valor 2.

...

Añade a la clase «Persona» un nuevo método «saludar», que reciba un parámetro, que será el texto que debe decir esa persona cuando salude.

...

Ampliar la clase «Libro» para que tenga un segundo inicializador que permita dar valores al autor y al título, pero no a la ubicación, que tomará el valor por defecto «No detallada».

...

Crear dos nuevos métodos en la clase «Vehiculo»: uno llamado «circular», que fijará su «velocidad» (un nuevo atributo) a 50, y otro «circular(v)», que fijará su velocidad al valor que se indique como parámetro.

...

Escribe una clase llamada «Mensaje» que guarde un «remite», «destino» y «contenido» de tipo String y una fecha de tipo entero (aaaammdd). El remite, destino y contenido deberán tener funciones para consultar y actualizar sus valores, pero las funciones «getFecha» y «setFecha» deberán manipular el valor de la fecha antes de guardarlo y antes de mostrarlo. Se deberá desarrollar un método «mostrar» para imprimir el mensaje de la siguiente forma:

Fecha: dd/mm/aaaa
Remite: xxxxxxxxxx, Destino: xxxxxxxxxx
Mensaje: xxxxxxxxxx

Se deberá crear una clase adicional «PruebaMensaje» donde se pidan los datos del mensaje y se muestren por pantalla. La fecha se deberá pedir en formato «dd/mm/aaaa», y se deberá convertir a un entero con el formato mencionado (se puede utilizar el método «split» del tipo String para separar el día, el mes y el año).

...

Crea una clase llamada «Tablero» que tendrá un atributo llamado «color» y otro llamado «material». Se deberá crear otra clase llamada «Mesa» que tendrá un atributo para guardar el tipo de tablero que tiene. En la mesa además se deberán guardar otros atributos como «altura» y «anchura». El tablero deberá tener un inicializador que asigne los valores por defecto de color «marrón» y material «madera». Se deberán desarrollar los métodos correspondientes para actualizar y consultar las propiedades, y un método mostrar en la clase «Mesa» que muestre todos sus datos, incluyendo los del tablero con el que está hecha. Además, se deberá probar dicho código con una clase adicional.

...

Un centro cultural se dedica al préstamo de dos tipos de materiales de préstamo: discos y libros. Para los dos se debe guardar información general, como su código identificativo, el título y el autor. En el caso de los libros, almacenaremos también su número de páginas, y para los discos, el nombre de la discográfica. Al centro cultural acuden una serie de clientes, de los que se guarda su DNI y nombre, que realizan una serie de peticiones de discos o libros, como mucho hasta 5 peticiones. Para cada petición se guarda la fecha de inicio y fin del préstamo. Crea todas las clases necesarias y los métodos para gestionar toda esta información, junto con una clase adicional para probarlo. Se necesitarán métodos del estilo «agregaPeticion» que añadirá una petición nueva dentro del cliente, comprobando que no llegue al máximo de préstamos.

...

Traductor español-inglés muy sencillo con Swift

Modo consola

Introduce una palabra: coche
Traducción: car

Introduce una palabra: car
Traducción: coche

Introduce una palabra: casa
Traducción: house

Introduce una palabra: dog
Traducción: perro

Introduce una palabra: aaaa
Traducción: palabra no encontrada

Introduce una palabra:
...
var palabras = [("coche", "car"), 
                ("gato",  "cat"),
                ("perro", "dog"),
                ("casa", "house")]

func traduce(_ entrada:String) -> String {
    for palabra in palabras {
        if palabra.0 == entrada { return palabra.1 }
        else if palabra.1 == entrada { return palabra.0 }
    }
    return "palabra no encontrada"
}

repeat {
    print("Introduce una palabra: ", terminator:"")
    let entrada = readLine()!
    let salida = traduce(entrada)
    print("Traducción: \(salida)\n")
}
while true

Aplicación iOS

Traducir con el evento de cambio de texto

//
//  ViewController.swift
//  Traductor
//

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    var palabras = [("coche", "car"),
                    ("gato",  "cat"),
                    ("perro", "dog"),
                    ("casa", "house")]

    @IBOutlet var traduccion: UILabel!
    
    func traduce(_ entrada:String) -> String {
        for palabra in palabras {
            if palabra.0 == entrada { return palabra.1 }
            else if palabra.1 == entrada { return palabra.0 }
        }
        return "palabra no encontrada"
    }
    
    @IBAction func traduce(_ entrada: UITextField) {
        traduccion.text = traduce(entrada.text!)
    }
}

Traducir al pulsar un botón

//
//  ViewController.swift
//  Traductor
//

import UIKit

class ViewController: UIViewController {

    @IBOutlet var entrada: UITextField!
    @IBOutlet var salida: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    var palabras = [("coche", "car"),
                    ("gato",  "cat"),
                    ("perro", "dog"),
                    ("casa", "house")]
    
    func traduce(_ entrada:String) -> String {
        for palabra in palabras {
            if palabra.0 == entrada { return palabra.1 }
            else if palabra.1 == entrada { return palabra.0 }
        }
        return "palabra no encontrada"
    }

    @IBAction func boton(_ sender: UIButton) {
        salida.text = traduce(entrada.text!)
    }
}

Utilizando una clase y una estructura para añadir nuevas palabras y guardar el diccionario

Instalación de La librería «Disk»

Vamos a proceder a instalar la librería «Disk» utilizando el gestor de librerías «CocoaPods«:

  • Crear un proyecto de Xcode del tipo «TabbedApp»
  • Abre un terminal y ves al directorio del proyecto utilizando el comando $ cd .
  • Crear el fichero Podfile utilizando el comando $ pod init.
  • Abre el fichero «Podfile». La primera línea debe indicar la plataforma y la versión de iOS:  platform :ios, '12.2'.
  • Añade la línea pod 'Disk' dentro de la sección target.
  • Guarda el fichero.
  • Instala la librería con la instrucción $ pod install .
  • Abre el fichero .xcworkspace que se ha creado. A partir de ahora deberemos abrir ese fichero en vez del .xcodeproj .

El contenido final del archivo «Podfile» sería el siguiente:

platform :ios, '12.2'

target 'traductor' do
  use_frameworks!

  # Pods for Traductor
  pod 'Disk'
end

Diccionario.swift

//
//  Diccionario.swift
//  Traductor
//

import Disk

struct Palabra : Codable {
    let es : String
    let en : String
}

class Diccionario {
    var palabras : [Palabra] = []
    
    func add(_ palabra:Palabra) {
        self.palabras += [palabra]
    }
    
    func traduce(_ entrada:String) -> String {
        for palabra in self.palabras {
            if palabra.es == entrada { return palabra.en }
            else if palabra.en == entrada { return palabra.es }
        }
        return "palabra no encontrada"
    }
    
    func guarda() {
        do {
            try Disk.save(self.palabras, to: .applicationSupport, as: "diccionario.json")
        }
        catch {
            print("Error guardando")
        }
    }
    
    func lee() {
        do {
            try self.palabras = Disk.retrieve("diccionario.json", from: .applicationSupport, as: [Palabra].self)
        }
        catch {
            print("Error leyendo")
        }
    }
}

AppDelegate.swift

//
//  AppDelegate.swift
//  Traductor
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var diccionario = Diccionario()
    
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        self.diccionario.lee()
        
        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
    }

    func applicationWillTerminate(_ application: UIApplication) {
    }
}

FirstViewController.swift

//
//  FirstViewController.swift
//  Traductor
//

import UIKit

class FirstViewController: UIViewController {

    var diccionario : Diccionario! = nil
    
    @IBOutlet var traduccion: UILabel!
    @IBOutlet var entrada: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        
        self.diccionario = appDelegate.diccionario
        
        print(self.diccionario.traduce("dog"))
    }

    @IBAction func traducir(_ sender: UITextField) {
        traduccion.text! = self.diccionario.traduce(sender.text!)
    }
}

SecondViewController.swift

//
//  SecondViewController.swift
//  Traductor
//

import UIKit

class SecondViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet var palabras: UITableView!

    var diccionario : Diccionario! = nil

    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.palabras.dataSource = self
        self.palabras.delegate = self

        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        
        self.diccionario = appDelegate.diccionario
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return diccionario.palabras.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: UITableViewCell.CellStyle.default, reuseIdentifier: "cell")
        cell.textLabel?.text = diccionario.palabras[indexPath.row].es + ", " + diccionario.palabras[indexPath.row].en
        return cell
    }
    
    @IBAction func addPalabra(_ sender: UIButton) {
        let alert = UIAlertController(title: "Añadir palabra", message: "", preferredStyle: .alert)
        
        alert.addTextField { (UITextField) in
            UITextField.placeholder = "Palabra en español"
        }

        alert.addTextField { (UITextField) in
            UITextField.placeholder = "Palabra en inglés"
        }
        
        alert.addAction(UIAlertAction(title: "Añadir", style: .default, handler: { (UIAlertAction) in
            let es = alert.textFields![0] as UITextField
            let en = alert.textFields![1] as UITextField
            self.diccionario.add(Palabra(es:es.text!, en:en.text!))
            self.diccionario.guarda()
            self.palabras.reloadData()
        }))
        
        alert.addAction(UIAlertAction(title: "Cancelar", style: .destructive, handler: nil))
        
        self.present(alert, animated: true, completion: nil)
    }
}

Cómo borrar palabras del diccionario

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath)
{
    if editingStyle == UITableViewCell.EditingStyle.delete {
        self.diccionario.palabras.remove(at: indexPath.row)
        self.diccionario.guarda()
        self.palabras.reloadData()
    }
}

Calculadora con Swift

Modo consola

Primer número: 1
Operación: +
Segundo número: 4
Resultado: 5

Primer número: r
Error

Primer número: 4
Operación: m
Error

Primer número: 1
Operación: /
Segundo número: 0
No se puede dividir por cero

Primer número: 4
Operación: -
Segundo número: 6
Resultado: -2

Primer número: 
...
enum OperacionCalculadora {
    case sumar, restar, multiplicar, dividir
    
    init?(_ boton:String) {
        switch boton {
            case "+": self = .sumar
            case "-": self = .restar
            case "*": self = .multiplicar
            case "/": self = .dividir
            default: return nil
        }
    }
    
    func calcular(_ n1: Int, _ n2: Int) -> Int {
        switch self {
            case .sumar: return n1 + n2
            case .restar: return n1 - n2
            case .multiplicar: return n1 * n2
            case .dividir: return n1 / n2
        }
    }
}

var n1:Int? = 0, n2:Int? = 0
var operacion:OperacionCalculadora? = nil
var pantalla:String = "0"

func actualizaNumero(_ boton:String) -> Int? {
    n1 = Int(pantalla)
    n2 = Int(boton)
    if n2 != nil {
        pantalla = boton
    }
    return n2
}

func actualizaOperacion(_ boton:String) -> OperacionCalculadora? {
    operacion = OperacionCalculadora(boton)
    return operacion
}

func realizaCalculo() -> Bool {
    if n2 == 0 && operacion == .dividir {
        print("No se puede dividir por cero\n")
        return false
    }
    pantalla = String(operacion!.calcular(n1!, n2!))
    return true
}

repeat {
    print("Primer número: ", terminator:"")
    if actualizaNumero(readLine()!) == nil {
        print("Error\n")
        continue 
    }
    print("Operación: ", terminator:"")
    if actualizaOperacion(readLine()!) == nil {
        print("Error\n")
        continue
    }
    print("Segundo número: ", terminator:"")
    if actualizaNumero(readLine()!) == nil {
        print("Error\n")
        continue 
    }
    
    if realizaCalculo() == true {
        print("Resultado: " + pantalla + "\n")
    }
} while true

Aplicación iOS

//
//  ViewController.swift
//  Calculadora
//

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet var pantalla: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    enum OperacionCalculadora {
        case sumar, restar, multiplicar, dividir
        
        init?(_ boton:String) {
            switch boton {
                case "+": self = .sumar
                case "-": self = .restar
                case "*": self = .multiplicar
                case "/": self = .dividir
                default: return nil
            }
        }
        
        func calcular(_ n1: Int, _ n2: Int) -> Int {
            switch self {
                case .sumar: return n1 + n2
                case .restar: return n1 - n2
                case .multiplicar: return n1 * n2
                case .dividir: return n1 / n2
            }
        }
    }
    
    var n1:Int? = 0, n2:Int? = 0, borraNumero = false
    var operacion:OperacionCalculadora? = nil
    
    // Ejecutar al pulsar los botones del 0 al 9
    @IBAction func actualizaNumero(_ boton:UIButton) {
        if pantalla.text == "0" || borraNumero == true {
            pantalla.text = ""
            borraNumero = false
        }
        pantalla.text = pantalla.text! + boton.currentTitle!
    }
    
    // Ejecutar al pulsar los botones de +, -, *, /
    @IBAction func actualizaOperacion(_ boton:UIButton) {
        operacion = OperacionCalculadora(boton.currentTitle!)
        n1 = Int(pantalla.text!)!
        borraNumero = true
    }
    
    // Ejecutar al pulsar el botón de =
    @IBAction func realizaCalculo() {
        n2 = Int(pantalla.text!)!
        if n2 == 0 && operacion == .dividir {
            muestraError("No se puede dividir por cero")
        }
        else {
            pantalla.text = String(operacion!.calcular(n1!, n2!))
        }
        borraNumero = true
    }

    func muestraError(_ mensaje:String) {
        let alert = UIAlertController(title:"Error", message:mensaje, preferredStyle:.alert)
        
        let action = UIAlertAction(title:"OK", style:.default, handler:nil)
        
        alert.addAction(action)
        
        show(alert, sender:nil)
    }
}

Swift – Ejercicios propuestos (I)

Pedirle un número al usuario y decir si es par usando «if»

var numero:Int;

print("Dime un número: ", terminator:"")
numero = Int(readLine()!)!

// Comprobamos si es par
if numero % 2 == 0 {
	print("\(numero) es par")
}
else {
    print("\(numero) no es par")
}

Pedirle dos números al usuario y ver cuál es el mayor de ellos


Pedirle al usuario un número. Si es múltiplo de 10, pedirle un segundo número y comprobar si también es múltiplo de 10

var numero1 = 0
var numero2 = 0

print("Dime el primer numero: ", terminator:"")
numero1 = Int(readLine()!) ?? 0 

if numero1 % 10 == 0 {
    print("\(numero1) es multiplo de 10, dame otro numero: ", terminator:"")
    numero2 = Int(readLine()!) ?? 0 
    
    if numero2 % 10 == 0 {
        print("El número \(numero2) también es múltiplo de 10\n")
    }
    else {
        print("El número \(numero2) no es múltiplo de 10\n")
    }
}
else {
    print("El número \(numero1) no es múltiplo de 10\n")
}

Multiplicar dos números si el primero no es cero (si es cero, avisar de que el resultado será cero)

var numero1 = 0
var numero2 = 0

print("Dime el primer numero: ", terminator:"")
numero1 = Int(readLine()!) ?? 0 

print("Dime el segundo numero: ", terminator:"")
numero2 = Int(readLine()!) ?? 0 

if numero1 == 0 || numero2 == 0 {
    print("Te va a dar cero\n")
}
else {
    print("La multiplicación de \(numero2) y \(numero1) es \(numero1*numero2)\n")
}

Pedirle al usuario un número e indicar si es múltiplo de 2 o de 3 (de cualquiera de ellos, sin importar cuál)

print("Dime un numero: ", terminator:"")
var numero = Int(readLine()!) ?? 0 

if numero % 2 == 0 || numero % 3 == 0 {
    print("El \(numero) es multiplo de 2 o de 3")
}
else {
    print("El \(numero) no es multiplo ni de 2 ni de 3")    
}

Pedirle al usuario un número e indicarle si es múltiplo de 2 y de 3 (a la vez)

print("Dime un numero: ", terminator:"")
var numero = Int(readLine()!) ?? 0 

if numero % 2 == 0 && numero % 3 == 0 {
    print("El \(numero) es multiplo de 2 y de 3")
}
else {
    print("El \(numero) no es múltiplo de 2 y 3 al mismo tiempo")    
}

Pedirle al usuario un número e indicarle si es múltiplo de 2 pero no de 3


Pedirle al usuario un número e indicarle si no es múltiplo de 2 ni de 3


Pedirle al usuario dos números e indicarle si ambos son pares


Pedirle al usuario dos números e indicarle si al menos uno es par


Pedirle al usuario dos números e indicarle si uno y solo uno es par


Pedirle al usuario que escriba dos números e indicarle uno de estos casos: Uno de ellos (pero no los dos) es positivo, los dos son positivos, o ninguno es positivo


Pedirle al usuario que escriba tres números e indicarle cuál es el mayor


Pedirle al usuario que escriba dos números e indicarle si son iguales o cuál es el mayor

var numero1 = 0
var numero2 = 0

print("Dime el primer numero: ", terminator:"")
numero1 = Int(readLine()!) ?? 0 

print("Dime el segundo numero: ", terminator:"")
numero2 = Int(readLine()!) ?? 0 

if numero1 == numero2 {
    print("Los dos números son iguales\n")
}
else if numero1 > numero2 {
    print("El numero \(numero1) es mayor que \(numero2)\n")
}
else {
    print("El numero \(numero2) es mayor que \(numero1)\n")
}

Usar el operador condicional ?: para mostrar el valor absoluto de un número


Usar el operador condicional ?: para detectar el menor de dos números


Utilizar un switch para pedirle al usuario un número del 1 al 10 y escribirlo en letra («uno», «dos», etc.)


Utilizar switch para pedirle al usuario un carácter e indicar el tipo: cifra numérica, signo de puntuación y otro carácter


Utilizar un switch para pedirle al usuario una letra y ver si ha escrito una vocal, un dígito o una consonante


Pedirle al usuario su contraseña numérica mientras no escriba 1111


Pedir un número por teclado e imprimir el cuadrado de dicho número


Pedirle al usuario dos números continuamente y ver cuál es múltiplo de cuál, o si no son múltiplos


Contador descendente de números pares del 26 al 10, usando while


Calcular cuántas cifras tiene un número entero positivo


Utilizando un bucle de tipo repeat while, sumar números positivos hasta que introduzcamos un 0 o un número negativo

var numero:Int, total = 0

repeat {
    print("Dime un numero: ", terminator:"")
    numero = Int(readLine()!) ?? 0 
    total += numero
} while numero > 0

print("Total sumado: \(total)")

Utilizando un bucle de tipo repeat while, pedirle al usuario su identificador y contraseña hasta que no escriba 1234 y 1111 respectivamente


Utilizando un bucle repeat while, pedirle al usuario su identificador y contraseña hasta que no escriba Pedro y Peter respectivamente


Mostrar los números del 10 al 20 ambos incluidos


Contar del 1 al 50 usando for y decir cuales son múltiplos de 3


Mostrar los números divisibles entre 7 y 3 que estén entre el 100 y el 200, usando un bucle for in


Imprimir la tabla de multiplicar del 9 usando for in


Mostrar los 8 primeros números pares


Mostrar del 15 al 5 descendiendo


Bucle infinito para mostrar «Hola» sin parar en pantalla


Bucle infinito para mostrar los enteros positivos a partir del 1


Utilizando bucles anidados, mostrar si los números estre el 10 y el 20 son divisibles entre 5, 6 o 7


Utilizando bucles anidados, mostrar 10 veces los números del 1 al 5, en 10 líneas separadas


Dibujar un cuadrado de asteriscos del ancho y alto que diga el usuario


Imprimir un rectángulo de asteriscos del ancho y alto especificado por el usuario


Dibujar un triángulo de asteriscos creciente, de tantas alturas como diga el usuario


Dibujar un triángulo de asteriscos decreciente, de tantas alturas como diga el usuario


Imprimir los divisores comunes de dos números


Imprimir el máximo común divisor de dos números


Imprimir el máximo común divisor de dos números utilizando un break para terminar cuando se haya encontrado


Imprimir el mínimo común múltiplo de dos números


Imprimir el mínimo común múltiplo de dos números utilizando un break para terminar cuando se haya encontrado


Imprimir una cuenta atrás desde el número introducido por teclado (entre el 1 y el 10)


Adivinar un número prefijado en el programa


Adivinar un número del 1 al 100 (prefijado) en 6 intentos como máximo


Averiguar si un número dado por el usuario es primo


Imprimir los factores primos de un número dado por el usuario


Calcular un número elevado a otro usando multiplicaciones sucesivas


Dibujar un rectángulo hueco, utilizando la altura y la anchura proporcionadas por el usuario


Devolver el cambio de una compra con los billetes y monedas más grandes posibles


Pedirle al usuario edad y año de nacimiento y dar aviso de error en el momento en que introduzca un dato incorrecto (por ejemplo, que ponga «Hola» al pedirle la edad)


Hallar el volumen de una esfera dado su radio. Volumen = pi * radio al cubo * 4/3


Mostrar el valor de y para los primeros 20 valores de x: y = x2 – 1


Calcula el perímetro, área y diagonal de un rectángulo dados su ancho y alto


Pedir al usuario su nombre y su contraseña dos veces, hasta que las dos contraseñas introducidas coincidan


Utilizando funciones

Crear una función que reciba como parámetro la longitud del lado de un cuadrado y lo dibuje utilizando asteriscos


Crear una función que reciba como parámetros la base y la altura de un rectángulo y lo dibuje utilizando asteriscos


Crear una función que reciba como parámetros un carácter y un número y repita ese carácter tantas veces como indique el número


Crear un función que devuelva el cubo de un número real pasado por parámetro


Crear una función para pedirle un número al usuario. Dicha función debe recibir como parámetro el texto a mostrar al usuario y el límite inferior y superior del entero que éste debe introducir, y repetirle que lo introduzca hasta que ponga un número correcto


Crear una función que reciba un entero y devuelva un booleano indicando si el número es primo o no


Swift – Opcionales

Introducción

Como hemos comentado previamente, una de las ventajas que nos da Swift es la posibilidad de escribir código seguro. Esto implica que swift está preparado para que las aplicaciones no se encuentren con situaciones indeseadas al momento de ejecutar el código. Los opcionales son un mecanismo muy importante para conseguir este objetivo.

Los opcionales permiten indicar que un valor puede estar ausente. Esto significa que una variable opcional puede tener un valor y por lo tanto se puede acceder al mismo o que esa variable esta “vacía”.

La potencia de este enfoque es que si se sabe que una variable puede llegar a no tener valor en algún momento de su ciclo de vida, podemos escribir código adicional preguntando si ese valor existe o no, estando seguros en todo momento sobre qué hacer en cada caso.

Si no existieran los opcionales, puede darse el caso de que no contemplemos un escenario en donde el valor no exista y por lo tanto se generen comportamientos extraños en momentos de ejecución. Veamos un ejemplo:

let colores = ["azul", "negro", "verde", "rojo", "amarillo"]

let primerColor = colores.first

//primerColor es es String? en lugar de String

Primero definimos un array de String donde guardamos un listado de colores y luego, creamos una constante para obtener el primero color del arreglo usando la propiedad first.

Como puede darse el caso de que el array esté vacío, first no siempre va a devolver un valor; en algunos casos tomará el primer elemento pero en otros indicará que no se encontró un valor. Esto hace que el resultado sea un opcional.

nil

Volviendo al ejemplo anterior, para indicar la ausencia de un valor se usa un valor especial llamado nil.

Por lo tanto, la constante primerColor no se trata de un tipo String sino de un opcional de String, indicado con un signo de pregunta (?) String?.

Si quisiéramos definir una variable como opcional usamos la siguiente forma:

var segundoColor: String? = "negro"
print("\(segundoColor)")

//Devuelve:
//Optional(“negro”)

segundoColor = nil
print("\(segundoColor)")

//Devuelve:
//nil

Como vemos, definimos la variable indicando el tipo de dato y agregando un signo de pregunta para indicar que se trata de un opcional.

La asignación de un valor en ese momento es optativo, ya que de no hacerlo Swift infiere que su valor inicial es nil.

Si imprimimos esa variable usando print vemos que su valor es Optional(“negro”) en lugar de “negro” a secas.

Una variable opcional puede volver a valer nil si es necesario.

Recordemos que las variables no opcionales deben tener un valor al momento de su definición obligatoriamente.

Forced unwrapping

Si sabemos y estamos seguros que en un determinado momento una variable opcional tiene un valor en su interior, podemos usar la técnica de forced unwrapping (desenvoltura forzada) mediante el uso de un signo de exclamación al final del nombre de la variable (!):

var otroColor:String? = "celeste"
print(“\(otroColor!)”)
//Devuelve
//celeste

Como sabemos que la variable otroColor contiene un valor, usamos la desenvoltura forzada y accedemos al dato que el mismo encierra. Ya no estamos obteniendo un Optional(“celeste”) sino que directamente obtenemos “celeste”.

Si quisiéramos preguntar primero si esa variable vale nil o no, una posibilidad es usar una sentencia if:

if otroColor != nil {
    print("\(otroColor!)")
}

//Devuelve
//celeste

En este caso, primero nos aseguramos si la variable no vale nil (o sea, si tiene un valor) y luego hacemos el forced unwrapping, debido a que dentro del ifestamos seguros que esa variable tiene un valor.

Optional Binding

Si bien el enfoque anterior es perfectamente válido, no termina siendo muy cómodo si dentro del if se necesita usar muchas veces el valor dentro del opcional, ya que tendríamos que recordar de usar el ! en todos los casos.

Otra manera de hacer lo mismo pero un poco más eficiente es usando el optional binding (enlace opcional), en el cual se pregunta si un opcional contiene un valor y en caso afirmativo, se crea una constante o variable temporal para ser usada dentro del if o while como si se tratara de una versión no opcional. Una vez fuera de ese if o while, la misma deja de existir.

if let colorElegido = otroColor {
    print("El color elegido es \(colorElegido)")
}

//Devuelve:
//El color elegido es celeste

Como vemos, creamos una constante temporal llamada colorElegido que contiene el valor del opcional otroColor. Dentro del if usamos ese valor y ya fuera de él la constante ya no existe más.

Asimismo, podemos anidar varios enlaces opcionales e incluso usar otras comparaciones convencionales que devuelven true o false. Como resultado, sólo se ejecutarán las instrucciones dentro del if cuando todos los opcionales tengan un valor y todas las condiciones devuelvan true. Si alguno de estos casos no se da, el resultado final será false y no se ingresará al if.

let numeroPar = 30

if let colorElegido = otroColor, let numero = Int("45"), numeroPar < 50 {
    print("El color elegido es \(colorElegido) y el \(numeroPar) es menor a 50")
    print("\(numero)")
}

//Devuelve:
//El color elegido es celeste y el 30 es menor a 50
//45

Implicit unwrapped optionals

En muchas situaciones contamos con variables opcionales que en un momento determinado del programa son inicializados con un valor y que luego no van a volver a valer nil nunca más. Por tal motivo, es conveniente no tener que preguntar a cada instante si esa variable contiene un valor y hacer la desenvoltura correspondiente, ya que se asume que siempre se va a contener un valor.

Un ejemplo muy claro de este escenario se da cuando se programa para un sistema operativo como iOS, en donde los botones que vemos en pantalla al inicio de su ciclo de vida se crean en nil pero luego mientras se inicializan determinados componentes, las variables que hacen referencia a esos botones contienen valor, hasta tanto el usuario cambia de pantalla y se pierden esas referencias. Como en un momento de su ciclo de vida necesitó valer nil, es obligatorio usar un opcional, pero como luego siempre va a tener un valor, no es cómodo tener que usar un if let en cada uso. Para este tipo de casos, los implicity unwrapped optionals (opcionales desenvueltos en forma implícita) son ideales.

Para hacer uso de ellos, en lugar de declarar al opcional usando un signo de pregunta (?) se utiliza un signo de exclamación (!):

let posibleValor:String? = "Estamos aprendiendo Swift! Yeahh!"
let valorSeguro:String! = posibleValor!

print(posibleValor)
print(valorSeguro)

//Devuelve:
//Optional("Estamos aprendiendo Swift! Yeahh!")
//Estamos aprendiendo Swift! Yeahh!

Podríamos decir que este tipo de opcionales tienen realizan la desenvoltura de su valor en forma automática, sin necesidad de hacerlo explícito. Tengamos en cuenta que si una variable o constante vale nil e intentamos usar su valor, vamos a tener un error en tiempos de ejecución. Por lo tanto, hay que ser muy cuidadoso y pensar bien antes de usar este tipo de opcionales.

En el caso de que exista alguna posibilidad de que una variable se vuelva nil en algún momento del código, entonces no debemos usar este opcional implícito.

Por otro lado, si necesitamos preguntar si ese opcional implícito tiene un valor en su interior o si quisiéramos usar el optional binding, podemos hacerlo:

if valorSeguro != nil {
    print(valorSeguro)
}

if let dato = valorSeguro {
    print(dato)
}

nil-coalescing operator

Este operador, que podríamos traducirlo como operador que viene junto a nil, devuelve el valor que contiene un opcional haciendo una desenvoltura (a) y en caso de encontrar nil, devuelve otro valor (b). Su sintaxis es a ?? b.

Un punto a tener en cuenta es que tanto a como b deben ser del mismo tipo.

var animal:String? = "Perro"

let mascota = animal ?? "Gato"

print("\(mascota)")

//Devuelve Perro

En el ejemplo, definimos una variable opcional animal con el valor Perro. Al ser opcional, podría no contener un valor (ser nil). Luego se declara una constante mascota que va a valer Perro siempre que la variable animal tenga ese valor. En caso de ser nil, se incluye un valor adicional Gato.

Este operador es muy útil cuando queremos dar un valor por defecto en caso de que una variable o contante no tengan valor.

Swift – Ejercicios resueltos (II)

Funciones y operadores aritméticos

Sumar dos números y devolver el resultado:

func suma(_ num1:Int, _ num2:Int) -> Int {
    return num1 + num2
}
let num1 = 5
let num2 = 8
print("\(num1) + \(num2) = \(suma(num1, num2))")

Calcular el número de segundos que suman en total un número determinado de años:

func segundosAnyo(_ anyos:Int) -> Int {
    let dias = 365
    let horas = 24
    let segundos = 3600
    return dias * horas * segundos * anyos
}
let anyos = 3
print("La cantidad de segundos en \(anyos) años es \(segundosAnyo(anyos))")

Calcular la cantidad total de píxeles que tiene una pantalla dada su altura y anchura en píxeles:

func pixeles(alto:Int, ancho:Int) -> Int {
    return(alto * ancho)
}
let alto = 720
let ancho = 480
print("La cantidad de píxeles de una pantalla de \(alto)x\(ancho) es \(pixeles(alto:720, ancho:480))")

Intercambiar el valor de dos variables:

func intercambiar(_ a:inout Int, _ b:inout Int) {
    let aux = a
    a = b
    b = aux
}
var num1 = 5
var num2 = 10
intercambiar(&num1, &num2)
print("El primer número es: \(num1) y el segundo es: \(num2)")

Dado un número, imprimir el último dígito:

func ultimo(_ num:Int) -> Int {
    return num % 10
}
let num = 2479
print("La última cifra de \(num) es \(ultimo(num))")

Dada la edad de un perro, calcular la edad equivalente en humanos, teniendo en cuenta que un año para una persona equivale a 7 años para un perro:

func edadHumano(_ edadPerro:Int) -> Int {
    return edadPerro * 7
}
let edadPerro = 7
print("\(edadPerro) años de un perro equivalen a \(edadHumano(edadPerro)) años de un humano")

Funciones y control de flujo

Dado un número, comprobar si es par o no:

func esPar(_ num:Int) -> Bool {
    return num % 2 == 0
}

let num = 24

// Con if
if esPar(num) {
    print("El numero \(num) es par")
}
else {
    print("El numero \(num) es impar")
}

// Con el operador ?
print("El numero \(num) es " + (esPar(num) ? "par" : "impar"))

Dados dos números, comprobar si el primero es divisible entre el segundo:

func esDivisible(_ num1:Int, _ num2:Int) -> Bool {
    return num2 != 0 && num1 % num2 == 0
}

let num1 = 3
let num2 = 1

// Con if
if esDivisible(num1, num2) {
    print("El número \(num1) es divisible entre \(num2)")
}
else {
    print("El número \(num1) no es divisible entre \(num2)")
}

// Con el operador ?
print("El número \(num1) \(esDivisible(num1, num2) ? "" : "no") es divisible entre \(num2)")

Funciones y tuplas

Dada una cantidad determinada de chicos y chicas, calcular el porcentaje de cada uno respecto al total:

func calcularPorcentajes(hombres:Int, mujeres:Int) -> (hombres:Int, mujeres:Int) {
    let total = hombres + mujeres
    let porcentajeHombres = (hombres * 100) / total
    let porcentajeMujeres = (mujeres * 100) / total

    return (porcentajeHombres, porcentajeMujeres)
}

let hombres = 12
let mujeres = 15
let porcentaje = calcularPorcentajes(hombres:12, mujeres:15)

print("De \(hombres + mujeres) personas, \(mujeres) son mujeres y \(hombres) son hombres, es decir, \(porcentaje.hombres)% de hombres y \(porcentaje.mujeres)% de mujeres")

Disponemos de dos tuplas de tipo (Int,Int) que representan dos fracciones. El primer valor en cada tupla representa el numerador y el segundo valor representa el denominador. Utilizando una función, crear una nueva tupla también de tipo (Int,Int) que contenga el resultado de sumar las dos fracciones:

func suma(_ fraccion1:(Int, Int), _ fraccion2:(Int, Int)) -> (Int, Int) {
    let numerador = fraccion1.0 * fraccion2.1 + fraccion2.0 * fraccion1.1
    let denominador = fraccion1.1 * fraccion2.1 

    return (numerador, denominador)
}

let fraccion1 = (1, 2)
let fraccion2 = (2, 3)
print("La suma de \(fraccion1) y \(fraccion2) es \(suma(fraccion1, fraccion2)))

Escribir el código necesario para jugar a piedra, papel, tijeras, cumpliendo las siguientes especificaciones:

  • Se debe definir una enumeración con tres posibles casos:  .piedra.papel.tijeras.
  • Se debe definir una segunda enumeración con tres posibles casos:  .gana.empata.pierde.
  • Escribir una función que reciba la elección de cada jugador y devuelva el resultado correspondiente al primer jugador.
enum Mano {
    case piedra, papel, tijeras
}

enum Resultado {
    case gana, empata, pierde
}

func jugar(jugador1:Mano, jugador2:Mano) -> Resultado {
    if jugador1 == jugador2 { return .empata }

    if jugador1 == .piedra  && jugador2 == .tijeras || 
       jugador1 == .papel   && jugador2 == .piedra  ||
       jugador1 == .tijeras && jugador2 == .papel { return .gana }

    return .pierde
}

print(jugar(jugador1:.papel, jugador2:.tijeras))

Parámetros variádicos

Calcular la suma de un número indeterminado de fracciones:

func suma(_ fracciones:(Int, Int)...) -> (Int, Int) {
    var resultado = (0, 1)

    for fraccion in fracciones {
        resultado.1 *= fraccion.1
    }
    for fraccion in fracciones {
        resultado.0 += (resultado.1 / fraccion.1) * fraccion.0
    }    

    return resultado
}

print(suma((1,2), (3,4), (5,2), (4,3)))

Swift – Ejercicios resueltos (I)

Variables, constantes y operadores aritméticos

Dadas dos variables, calcular la suma, almacenar el resultado en otra variable e imprimir el resultado:

let num1 = 5
let num2 = 8
let suma = num1 + num2
print("\(num1) + \(num2) = \(suma)")

Calcular el número de segundos en un año almacenando dicho valor en una variable:

let dias = 365
let horas = 24
let segundos = 3600
let segundosAnyo = dias * horas * segundos
print("La cantidad de segundos en un año es \(segundosAnyo)")

Partiendo de la anchura y la altura de una pantalla en píxeles, calcular el número total de píxeles de dicha pantalla guardando el resultado en otra variable:

let alto = 720
let ancho = 480
let pixeles = alto * ancho
print("La cantidad de pixeles es \(pixeles)")

Dadas dos variables, intercambiar sus valores:

var num1 = 4
var num2 = 8

let aux = num2
num2 = num1
num1 = aux

print("El primer numero es: \(num1) y el segundo es: \(num2)")

Dado un número, imprimir el último dígito:

let num = 2479
print("La última cifra de \(num) es \(num % 10)")

Dada la edad de un perro, imprimir la edad equivalente en humanos, teniendo en cuenta que un año para una persona equivale a 7 años para un perro:

let edadPerro = 7
let edadHumano = edadPerro * 7
print("\(edadPerro) años de un perro equivalen a \(edadHumano) años de un humano")

Dada una cantidad determinada de chicos y chicas, imprimir el porcentaje de cada uno respecto al total:

let hombres = 12
let mujeres = 15
let total = hombres + mujeres

let porcentajeHombres = (hombres * 100) / total
let porcentajeMujeres = (hombres * 100) / total

print("De \(total) alumnos, \(mujeres) son mujeres y \(hombres) son hombres, es decir, \(porcentajeHombres)% de hombres y \(mujeres)% de mujeres")

Control de flujo

Dados dos números, compararlos e imprimir el mayor de ellos:

let num1 = 3
let num2 = 4
if num1 > num2 {
    print("El número \(num1) es mayor que \(num2)")
}
else if num2 > num1 {
    print("El número \(num2) es mayor que \(num1)")
}

Dado un número, imprimir un mensaje indicando si es par o impar:

let num = 23

// Con if
if num % 2 == 0 {
    print("El numero \(num) es par")
}
else {
    print("El numero \(num) es impar")
}

// Con el operador ?
print("El numero \(num) es " + (num % 2 == 0 ? "par" : "impar"))

Dados dos números, imprimir un mensaje diciendo si el primero es divisible entre el segundo o no:

let num1 = 3
let num2 = 1

if num2 != 0 && num1 % num2 == 0  {
    print("El número \(num1) es divisible entre \(num2)")
}
else if num2 != 0 && num1 % num2 != 0 {
    print("El número \(num1) no es divisible entre \(num2)")
}
else {
    print("No se puede dividir entre 0")
}

Dadas tres variables, comparar el valor que contienen e indicar si todas ellas son diferentes, o si por el contrario, dos variables o las tres contienen el mismo valor:

var a = 2
var b = 2
var c = 2

if (a == b) || (a == c) || (b == c) {
    print("Al menos dos variables tienen el mismo valor")
} else {
    print("Todas las variables tienen valores diferentes")
}

Disponemos de dos variables que indican los días que hace que hemos comprado leche y huevos respectivamente. Si hace más de 2 días que compramos la leche deberemos imprimir que ya está caducada, y si hace más de 7 días que compramos los huevos, imprimiremos que están caducados. Si la leche y los huevos no estén caducados, se deberá imprimir un mensaje indicando que ambos están en buen estado:

var diasLeche = 6
var diasHuevos = 12

if diasLeche <= 2 && diasHuevos <= 7 {
    print("La leche y los huevos están en buen estado")
} else {
    if diasLeche > 2 {
        print("La leche está caducada")
    }
    if diasHuevos > 7 {
        print("Los huevos están caducados")
    }
}

Dado un entero que indique un año cualquiera, indicar si dicho año es bisiesto o no, teniendo en cuenta que un año es bisiesto si es divisible entre 4 y no es divisible entre 100, y también si es divisible entre 400 (2000 y 2400 sí son bisiestos. 2100, 2200 y 2300 no lo son):

let anyo = 2018

let divisibleEntre4 = anyo % 4 == 0
let divisibleEntre100 = anyo % 100 == 0
let divisibleEntre400 = anyo % 400 == 0

if divisibleEntre4 && (!divisibleEntre100 || divisibleEntre400) {
    print("El año \(anyo) es bisiesto")    
}
else {
    print("El año \(anyo) no es bisiesto") 
}

Generar un número aleatorio entre 1 y 3 (ambos incluidos) simulando que lanzamos una moneda, de forma que se imprima uno de los tres posibles valores (cara, cruz o canto). Se puede utilizar la función random de la siguiente forma: Int.random(in:1...3)

let moneda = Int.random(in:1...3)

if      moneda == 1 { print("Cara")  } 
else if moneda == 2 { print("Cruz")  } 
else                { print("Canto") }

Dados cuatro valores numéricos, imprimir el más pequeño:

let a = 7, b = 4, c = 2, d = 6

var min = a

if b < min { min = b }

if c < min { min = c }

if d < min { min = d }

print(min)

Imprimir si un número es divisible entre 3 y 5 al mismo tiempo:

let numero = 135

// Con if
if numero % 3 == 0 && numero % 5 == 0 {
    print("\(numero) es divisible entre 3 y 5")
} else {
    print("\(numero) no es divisible entre 3 y 5")
}

// Con el operador ?
print("\(numero) \(numero % 3 == 0 && numero % 5 == 0 ? "" : "no") es divisible entre 3 y 5")

Escribir un switch que imprima las siguientes cadenas utilizando los siguientes intervalos dependiendo de una variable que contiene una distancia:

  1. «Aquí» si la distancia es 0.
  2. «Bastante cerca» si la distancia es mayor que 0 y menor que 5.
  3. «Cerca» si la distancia está entre 5 y 15.
  4. «Más o menos cerca» si la distancia está entre 15 y 40, ambos incluidos.
  5. «Lejos» si la distancia es mayor que 40.
let distancia:UInt = 15

switch distancia {
    case 0:
        print("Aquí")
    case 1..<5:
        print("Bastante cerca")
    case 5..<15:
        print("Cerca")
    case 15...40:
        print("Más o menos cerca")
    default:
        print("Lejos")
}

Tenemos una cadena que indica la descripción de un animal. Si el animal es un «gato» debemos imprimir un mensaje indicándolo. Si es un «gato muy grande», debemos decir que el animal tal vez sea un tigre, y en caso contrario indicaremos que es otro tipo de animal:

let animal = "gato muy grande"

switch animal {
    case "gato":
        print("El animal es un gato")
    case "gato muy grande":
        print("El animal tal vez es un tigre")
    default:
        print("El animal no es ni un gato ni un tigre")
}

Utilizando un switch imprimir la cadena «Eres un superhéroe» si tu nombre es «Clark Kent» o «Bruce Wayne», y «Eres una persona normal» en caso contrario:

let nombre = "Bruce Wayne"

switch nombre {
    case "Clark Kent", "Bruce Wayne":
        print("Eres un superhéroe")
    default:
        print("Eres una persona normal")
}

Arrays

Crear de dos formas diferentes un array que contenga los siguientes enteros 5, 8, 10, 16, 23, 40:

var array1: [Int] = [5, 8, 10, 16, 23, 40]
var array2 = [5, 8, 10, 16, 23, 40]
print(array1)
print(array2)

Crear de dos formas diferentes un array que no pueda ser modificado y que contenga los siguientes enteros: 5, 8, 10, 16, 23, 40

let array1: [Int] = [5, 8, 10, 16, 23, 40]
let array2 = [5, 8, 10, 16, 23, 40]
print(array1)
print(array2)

Añade de dos formas diferentes los valores 118, 137, y 5615 al final del siguiente array: [5, 8, 10, 16, 23, 40]

var array1 = [5, 8, 10, 16, 23, 40]
var array2 = [5, 8, 10, 16, 23, 40]
let array3 = [118, 137, 5615]

array1.append(contentsOf: array3)
array2 += array3

print(array1)
print(array2)

Reemplazar el valor 16 con el valor 45 en el siguiente array: [5, 8, 10, 16, 23, 40]

var array = [5, 8, 10, 16, 23, 40]

array[3] = 45 

print(array)

Reemplaza los valores 8, 10, y 16 con los valores 1, 2, 3, 4, 5 y 6 en el siguiente array: [5, 8, 10, 16, 23, 40]

var array = [5, 8, 10, 16, 23, 40]

array[1...3] = [1, 2, 3, 4, 5, 6]

print(array)

Enumeraciones y tuplas

Definir un array de tuplas que tengan 2 campos cada una, para guardar el nombre y primer apellido de 5 personas:

var personas = [(nombre: "Juan", apellido: "Rubio"),
                (nombre: "Pepe", apellido: "García"),
                (nombre: "Luis Enrique", apellido: "Peinado"),
                (nombre: "Álvaro", apellido: "Sánchez"),
                (nombre: "Pablo", apellido: "Ruiz")]                          

for persona in personas { print(persona) }

Partiendo de dos valores cualesquiera, formar una tupla indicando cuál de esos dos valores es el menor y cuál el mayor:

let a = 5, b = 6
let resultado = a < b ? (menor:a, mayor:b) : (menor:b, mayor:a)
print(resultado)

Definir una enumeración para tener un listado de varios tipos de dispositivos de Apple:

enum DispositivoApple {
    case iPhone
    case iPad
    case iWatch
}

let miDispositivo = DispositivoApple.iPhone
print(miDispositivo)

Disponemos de un array que indica los movimientos del personaje de un videojuego, y también conocemos su posición original. Un paso .arriba incrementará la coordenada y en 1. Un paso .abajo decrementará la coordenada y en 1. Un paso a la  .derecha incrementará la coordenada x en 1. Un paso a la .izquierda decrementará la coordenada x en 1. Se debe imprimir la ubicación final del personaje después de realizar los movimientos indicados:

enum Direccion {
    case arriba, abajo, izquierda, derecha
}

var ubicacion = (x: 0, y: 0)
let pasos:[Direccion] = [.abajo, .abajo, .derecha, .arriba]

for paso in pasos {
    switch paso {
        case .arriba:    ubicacion.y += 1
        case .abajo:     ubicacion.y -= 1
        case .derecha:   ubicacion.x += 1
        case .izquierda: ubicacion.x -= 1
    }
}

print(ubicacion)

Escribir el código necesario para jugar a piedra, papel, tijeras, utilizando una enumeración con los tres posibles casos:  .piedra.papel.tijeras:

enum Mano {
    case piedra, papel, tijeras
}

let jugador1 = Mano.papel
let jugador2 = Mano.tijeras

if jugador1 == jugador2 { 
    print("Empate") 
}
else if jugador1 == .piedra  && jugador2 == .tijeras || 
        jugador1 == .papel   && jugador2 == .piedra  ||
        jugador1 == .tijeras && jugador2 == .papel { 
    print("Gana jugador 1") 
}
else { 
    print("Pierde jugador 1") 
}

Utilizando una enumeración de tipos de monedas y un array de tuplas que especifique el número de monedas que tenemos de cada tipo, calcular e imprimir el cantidad total de dinero:

enum TipoMoneda {
    case cents5, cents10, cents20, cents50, euro1, euro2
}

let monedas:[(cantidad:Int,tipo:TipoMoneda)] = [(2,.cents10), (5,.euro1), (3,.euro2)]

var total = 0

for (cantidad, tipo) in monedas {
    switch tipo {
        case .cents5:
            print("\(cantidad) monedas de 5 céntimos")
            total += cantidad * 5
        case .cents10:
            print("\(cantidad) monedas de 10 céntimos")
            total += cantidad * 10
        case .cents20:
            print("\(cantidad) monedas de 20 céntimos")
            total += cantidad * 20
        case .cents50:
            print("\(cantidad) monedas de 50 céntimos")
            total += cantidad * 50
        case .euro1:
            print("\(cantidad) monedas de 1 euro")
            total += cantidad * 100
        case .euro2:
            print("\(cantidad) monedas de 2 euros")
            total += cantidad * 200
    }
}

print("Total: \(Double(total)/100.0) euros")

Disponemos de un array con los bocadillos que quieren pedir unos amigos en un bar. Antes de llamar al camarero se debe crear otro array que contenga tuplas indicando el tipo de bocadillo y el número de bocadillos que quieren pedir de ese tipo:

enum TipoBocadillo {
    case tortilla, calamares, queso
}

let bocadillos:[TipoBocadillo] = [.tortilla, .tortilla, .calamares, .queso, .calamares, .calamares, .queso]

var listaCamarero:[(tipo:TipoBocadillo, cantidad:Int)] = []

for bocadillo in bocadillos {
    var i = 0
    while i < listaCamarero.count {
        if (listaCamarero[i].tipo == bocadillo) {
            listaCamarero[i].cantidad += 1
            break
        }
        i += 1
    } 
    if i >= listaCamarero.count {
        listaCamarero += [(bocadillo, 1)]        
    }
}

for bocadillo in listaCamarero {
    print("\(bocadillo.cantidad) bocadillos de \(bocadillo.tipo)")
}

Swift – Enumeraciones

Definición

Las enumeraciones son un tipo de dato que permiten definir un grupo de valores relacionados bajo un nombre. Cada uno de estos valores dentro de la enumeración son llamados miembros o casos y poseen a su vez, un nombre que los identifica. Esto es, al definir una enumeración, se establecen los posibles estados que ese enum puede llegar a valer. Todos esos estados, o miembros, están relacionados entre sí.

Por ejemplo, si quisiera crear una variable sobre los puntos cardinales sabemos que, en principio, tiene cuatro posibles valores: Norte, Sur, Este y Oeste. Esos cuatro valores podrían ser miembros de un enum llamado PuntosCardinales y la variable a crear podría tomar uno de esos estados.

Sintaxis de las enumeraciones en Swift

Para definir una enumeración se utiliza la palabra reservada enum seguida del nombre de la misma.

Luego, el cuerpo de la enumeración se encierra entre llaves, como vemos a continuación:

enum Enumeracion {
    //Cuerpo de la enumeración
}

Para definir los miembros de una enumeración, se utiliza la palabra reservada case. Siguiendo el ejemplo de los puntos cardinales, su estructura sería la siguiente:

enum PuntoCardinal {
    case norte
    case sur
    case este
    case oeste
}

A su vez, cada caso puede definirse en una sola línea, usando una sola vez la palabra case y separando cada miembro por comas:

enum PuntoCardinal {
    case norte, sur, este, oeste
}

Convención de nombres para las enumeraciones en Swift

Al igual que las clases y las estructuras, las enumeraciones también son tipos de datos que creamos en nuestro código. Por lo tanto, el nombre que le asignemos debe comenzar con una mayúscula y, en caso de ser varias palabras, cada una de ellas debe separarse por mayúsculas sin usar guiones bajos u otro símbolo (camel case).

Otro punto a considerar es que el nombre de la enumeración debe estar en singular y nunca en plural. Esto es así ya que las enumeraciones se usan dentro de variables o constantes, por lo tanto solo pueden adoptar 1 valor a la vez. Siguiendo el caso anterior, si creamos una variable para el punto cardinal tendríamos lo siguiente:

var direccion = PuntoCardinal.norte

La lectura de la asignación anterior es muy clara. Se está eligiendo un punto cardinal de un listado de posibles valores y dicho valor se está guardando en la variable dirección.

Uso de las enumeraciones en Swift

Como vimos, tanto las variables como las constantes pueden ser del tipo de una enumeración. En su asignación inicial, debemos especificar el nombre del enum que vamos a usar y el valor que va a tomar dentro de la enumeración.

Supongamos que tenemos la siguiente enumeración:

enum DiaDeLaSemana {
    case lunes, martes, miercoles, jueves, viernes, sabado, domingo
}

Una posible asignación a una variable podría ser la siguiente:

var mañana = DiaDeLaSemana.martes

Como la variable mañana se inicia por primera vez, debemos especificar que su valor va a ser alguno de los contenidos dentro de la enumeración DiaDeLaSemana. Sin embargo, si quisiéramos modificar su valor, ya no es necesario volver a indicar el tipo de dato:

mañana = .miercoles

Como ya sabemos que mañana es un DiaDeLaSemana, directamente podemos asignarle otro valor dentro del enum usando un punto y el nuevo valor.

Comparar valores de las enumeraciones en Swift

Durante nuestro código, una vez que tengamos una variable con un cierto valor de los disponibles de una enumeración, vamos a necesitar preguntar por él para tomar una decisión.

Comparar con if

Podemos usar if para conocer el valor de la variable:

if mañana == DiaDeLaSemana.lunes {
print(«Se termina el fin de semana!»)
}

Asimismo, tal como vimos antes, podemos simplificar el código anterior sin mencionar el tipo de dato:

if mañana == .lunes {
    print("Se termina el fin de semana!")
}

Comparar con switch

Sin embargo, si tenemos una enumeración con varios casos y deseamos codificar un comportamiento para cada uno, usar un if no va a ser la mejor opción. En esos casos, conviene usar switch:

switch mañana {
    case .lunes:
        print("Mañana es lunes")
    case .martes:
        print("Mañana es martes")
    case .miercoles:
        print("Mañana es miércoles")
    case .jueves:
        print("Mañana es jueves")
    case .viernes:
        print("Mañana es viernes")
    case .sabado:
        print("Mañana es sábado")
    case .domingo:
        print("Mañana es domingo")
}
//Devuelve
//Mañana es miércoles

Cómo comentamos en el capítulo de control de flujo, la sentencia Switch necesita que los casos sean exhaustivos, es decir, que se contemplen todos los posibles valores que esa variable pueda tomar. Como la enumeración DiaDeLaSemana solo tiene 7 casos posibles, no hay riesgo de que una variable de ese tipo adopte otro valor distinto a esos 7, por lo tanto no es necesario usar un default.

Sin embargo, si no hiciéramos mención a los 7 valores en los cases, deberíamos incluir un default:

switch mañana {
    case .lunes:
        print(“Mañana es lunes”)
    case .martes:
        print(“Mañana es martes”)
    case .miercoles:
        print(“Mañana es miércoles”)
    case .jueves:
        print(“Mañana es jueves”)
    case .viernes:
        print(“Mañana es viernes”)
    default:
        print(“Mañana comienza el fin de semana”)
}
//Devuelve
//Mañana es miércoles

Enumeraciones con métodos

Al igual que en las clases y structs, podemos definir métodos dentro de los enums. Esta característica muestra la flexibilidad que las enumeraciones tienen en Swift y lo diferencia con las implementaciones en otros lenguajes de programación.

Los métodos que escribamos dentro de un enum siguen las mismas reglas que vimos en el capítulo de funciones.

enum Saiyan {
    case Goku, Vegeta, Gohan, Trunks

    func superPoder() -> String {
        switch self {
            case .Goku, .Gohan:
                return "Kamehameha"
            case .Vegeta, .Trunks:
                return "Garlic Ho"
        }
    }
}

let principeSaiyan = Saiyan.Vegeta
print("\(principeSaiyan.superPoder())")

//Devuelve
//Garlic Ho

Swift – Clases

Introducción

En este capítulo vamos a ver uno de los conceptos más importantes de la programación orientada a objetos: las clases. Su importancia radica en que todo programador debe diseñar un modelo de datos que soporte el comportamiento que requiere un determinado programa para resolver el problema para el cual es creado y las clases son justamente ideales para ello. En el siguiente capítulo vamos a ver las estructuras que tienen un comportamiento similar a las clases, sobre todo en Swift.

Según Wikipedia una clase es “una plantilla para la creación de objetos de datos según un modelo predefinido. Las clases se utilizan para representar entidades o conceptos, como los sustantivos en el lenguaje. Cada clase es un modelo que define un conjunto de variables -el estado, y métodos apropiados para operar con dichos datos -el comportamiento. Cada objeto creado a partir de la clase se denomina instancia de la clase”.

Como bien dice la definición, usamos las clases para definir un concepto. Dicho concepto forma parte del problema que queremos modelar y por lo tanto, del problema que queremos resolver al crear un programa. Para ello, las clases poseen distintos componentes, entre los que se destacan las propiedades y los métodos. Podemos decir que las propiedades son las características que poseen las clases mientras que los métodos son las acciones que podemos realizar.

Cada vez que creamos una clase, en realidad estamos creando un nuevo tipo de dato. Es por esto que se dice que este tipo de lenguajes es un lenguaje tipado, por la posibilidad que da al programador de crear nuevos tipos. Todo nombre de una clase debe, por convención, nombrarse con una mayúscula en su primer letra, mientas que las propiedades y métodos deben comenzar con minúscula.

Sintaxis de una clase

Para crear una clase se utiliza la palabra reservada class seguida del nombre de la misma:

class UnaClase {
}

Las propiedades son variables o constantes creados dentro del ámbito de una clase y su declaración sigue todas las reglas que vimos en los capítulos anteriores.

class Rectangulo {
    let lados = 4
    let alto = 5
    let ancho = 2
}

let figura = Rectangulo()
print("la figura contiene \(figura.lados) lados")

//Devuelve
//la figura contiene 4 lados

Como se aprecia en el ejemplo, para poder instanciar una clase basta con declarar una variable o constante y hacer una asignación usando el nombre de esa clase. En este caso, se usan paréntesis sin parámetros porque no se ha especificado que reciba ninguno. La clase Rectángulo posee tres propiedades numéricas con un valor asignado al momento de la creación de la clase.

Se dice que la constante figura representa un objeto o una instancia de la clase Rectángulo. La diferencia entre una clase y un objeto (o instancia) es que la clase simplemente es una definición, un concepto. Sin embargo, al momento de crear el objeto, se asigna un espacio en memoria para poder guardar todos los elementos que este define y por lo tanto, sus propiedades y métodos pueden ser usados.

Gracias a que figura es una instancia (y no una simple definición como lo es Rectángulo), podemos acceder a su propiedad lados e imprimir el resultado dentro de una cadena con la función print.

Inicialización de una clase

Si quisiéramos que las propiedades de la clase obtengan su valor al momento de crear la instancia, debemos utilizar un inicializador (lo que en otros lenguajes orientados a objetos se lo conoce como constructor). Mediante este elemento podremos, en el ejemplo, dar un valor a las propiedades alto y ancho para crear distintos tamaños de rectángulos al momento de crear una instancia.

Se define inicialización como el proceso de preparar la instancia de una clase. En él, podemos dar valores iniciales a las propiedades de la clase como así también ejecutar código para hacer un seteo inicial. Para poder usarlo, debemos usar un inicializador que se identifica por la palabra reservada init.

class Rectangulo {
    let lados = 4
    var alto:Int
    var ancho:Int

    init(al:Int, an:Int){
        alto = al
        ancho = an
    }
}

let figura = Rectangulo(al: 3, an: 6)
print("La figura mide \(figura.alto) x \(figura.ancho)")

//Devuelve:
//La figura mide 3 x 6

En el ejemplo usamos init para establecer un valor inicial para las propiedades alto y ancho. Luego, en el cuerpo del mismo usamos esos parámetros para asignárselos a las propiedades. Como se puede observar en el print, los valores se guardan en las variables correspondientes.

En el proceso de inicialización, no solamente se puede dar un valor inicial a las variables. Por el contrario, las constantes también pueden ser inicializadas aquí teniendo en cuenta que una vez que termine el proceso de init, las mismas deben quedar todas inicializadas (no pueden haber constantes sin valor) y luego nunca más podrán variar su contenido. Si quedaran constantes sin inicializar, se obtendría un error.

En el caso de querer dejar una variable sin inicializar incluso cuando ya finalizó la etapa del init, esa variable deberá ser un opcional, ya que en su ciclo de vida existen etapas donde su valor es nil.

Self

Si bien el ejemplo anterior obtiene perfectamente dos valores y los mismos son usados dentro del cuerpo del init, el nombre de los parámetros no siguen los criterios de nomenclatura que promueve Apple. Uno de los puntos más importantes de estos criterios es que el nombre de las variables, parámetros, constantes o cualquier otra estructura que usemos debe dar una idea del valor que contiene o del propósito para el cual fue creado.

En este sentido, los nombres utilizados para los parámetros del ejemplo (al y an) no dicen nada, y una persona que use nuestro código (o bien nosotros mismos más adelante) puede no entender de qué se trata. Por eso, sería más conveniente darles nombres más descriptivos, como alto y ancho respectivamente.

Ahora bien, ¿cómo diferenciamos las referencias alto y ancho de los parámetros con respecto al alto y ancho de las propiedades? Es decir, si en el cuerpo del init hiciéramos un “alto + alto”, ¿estaríamos haciendo referencia a la suma de los alto de los parámetros o de las propiedades?

Para evitar esta confusión existe la palabra reservada self. Con self hacemos referencia a los nombres de las propiedades de la clase. Por lo tanto, dentro de un init en donde el nombre de los parámetros coincide con el de las propiedades, decir self.alto hace referencia al alto de las propiedades, mientras que alto a secas referencia al parámetro.

Dicho esto, el siguiente ejemplo queda mucho más claro en cuanto a los nombres de los parámetros:

class Rectangulo {
    let lados = 4
    var alto:Int
    var ancho:Int

    init(alto:Int, ancho:Int){
        self.alto = alto
        self.ancho = ancho
    }
}

let figura = Rectangulo(alto: 3, ancho: 6)
print("La figura mide \(figura.alto) x \(figura.ancho)")

//Devuelve:
//La figura mide 3 x 6

Métodos de una clase

Los métodos son funciones escritas dentro del cuerpo de una clase que permiten darle un comportamiento a ésta, encapsulando tareas y proveyendo de un comportamiento a la instancia.

En Swift los métodos no son un componente exclusivo de las clases sino que también se pueden dotar de métodos a las estructuras y enumeraciones, como veremos más adelante.

Para crear un método, basta con crear una función dentro de la clase:

class Rectangulo {
    let lados = 4
    var alto:Int
    var ancho:Int

    init(alto:Int, ancho:Int){
        self.alto = alto
        self.ancho = ancho
    }

    func incrementarAlto() {
        alto += 1
    }
}

let figura = Rectangulo(alto: 3, ancho: 6)
figura.incrementarAlto()
print("La figura mide \(figura.alto) x \(figura.ancho)")

//Devuelve:
//La figura mide 4 x 6

En el ejemplo anterior, creamos un método que nos permite aumentar el alto del rectángulo en 1. Por lo tanto, al invocar a la función incrementarAlto() el valor de la propiedad Alto sube a 4.

Cabe destacar que los métodos siguen todas las reglas que vimos en el capítulo de funciones. Por consiguiente, podemos crear métodos con el mismo nombre pero distinta definición generando sobrecarga o usar etiquetas de argumento, por solo citar dos características:

class Rectangulo {
    let lados = 4
    var alto:Int
    var ancho:Int

    init(alto:Int, ancho:Int){
        self.alto = alto
        self.ancho = ancho
    }

    func incrementarAlto() {
        alto += 1
    }

    func incrementarAlto(en valor: Int) {
        alto += valor
    }
}

let figura = Rectangulo(alto: 3, ancho: 6)
figura.incrementarAlto(en: 6)
print("La figura mide \(figura.alto) x \(figura.ancho)")

//Devuelve:
//La figura mide 9 x 6

Herencia

Se trata de una propiedad que permite que una clase se cree a partir de otra, adoptando las características de la clase madre y agregando nuevas funcionalidades. Es especialmente útil cuando se elabora el diagrama de clases que se va a utilizar para resolver un problema determinado y que, consiguientemente, van a definir el comportamiento de la aplicación. Una clase puede heredar métodos, propiedades y otras características de la otra clase.

La herencia es una de las propiedades que diferencia a las clases de otros tipos, como las estructuras o las enumeraciones. Cuando una clase A hereda de B se dice que B es la súper clase y A la subclase.

Las subclases, por lo tanto, pueden hacer uso de la funcionalidad de la súper clase como si dicha funcionalidad se hubiera definido dentro de ella. Asimismo, la subclase puede sobreescribir las versiones de los métodos o propiedades en caso de ser necesario (proceso conocido como overriding).

Clase base

Se define clase base como aquella que no hereda de ninguna otra. Supongamos que tenemos la siguiente clase FiguraGeometrica:

class FiguraGeometrica {
    var color:String
    var area = 0.0
    var perimetro = 0.0

    init(color:String) {
        self.color = color
    }

    func calcularArea() {
        //No escribimos nada ya que cada figura tiene su propia fórmula
    }

    func calcularPerimetro() {
        //No escribimos nada ya que cada figura tiene su propia fórmula
    }

    func cambiar(color:String) {
        self.color = color
    }
}

En el ejemplo, la clase FiguraGeometrica define 3 propiedades: color, área y perímetro. El color es asignado en el init mientras que los otros dos son iniciados en 0. Por otro lado, se definen 3 métodos, pero dos de ellos no tienen código en su interior debido a que no disponen de los datos suficientes para poder hacer el cálculo, ya que cada figura geométrica posee su propia fórmula para calcular estas propiedades. Mientras tanto, lo único que sí sabemos a esta altura es que si se desea cambiar el color, simplemente recibiendo un nuevo color ya es suficiente para hacer el cambio.

La primera conclusión que sacamos es que en la clase base debemos incluir aquellas propiedades y métodos que son comunes en todas las clases heredadas.

Al momento de crear la clase FiguraGeometrica definimos todas las características comunes para una figura geométrica arbitraria. Para darle más comportamiento y un contexto más rico, es necesario crear clases más específicas que hereden de ella.

Para representar colores en una aplicación real se utilizan otras clases en lugar de String, pero para efectos del ejemplo vamos a usarlos como si solo se trataran de cadena de caracteres.

Subclases

Como ya dijimos, al crear una subclase se genera una nueva clase basada en otra, de la cual se heredan sus características. Estas pueden ser usadas como si fueran propias, pueden ser modificadas e incluso pueden agregarse nuevas características.

Para indicar que una subclase hereda de otra, se lo debe indicar al momento de definirla, usando : y el nombre de la súper clase:

class subClase: superClase {

}

Podemos tomar la clase Rectángulo usada en los ejemplos anteriores y hacer que herede de FiguraGeometrica:

class Rectangulo:FiguraGeometrica {
    let lados = 4
    var alto:Int
    var ancho:Int

    init(color:String, alto:Int, ancho:Int){
        self.alto = alto
        self.ancho = ancho
        super.init(color: color)
    }

    func incrementarAlto() {
        alto += 1
    }

    func incrementarAlto(en valor: Int) {
        alto += valor
    }
}

Un punto a tener en cuenta es que la súper clase tiene un inicializador distinto al de la subclase (espera un color mientras que la subclase espera un alto y un ancho). Por lo tanto, en el init de la clase Rectángulo se debe invocar al init de la súper clase como última sentencia, utilizando la palabra reservada super.

let rectangulo = Rectangulo(color: "Azul", alto: 9, ancho: 4)
print("El rectángulo mide \(rectangulo.alto) x \(rectangulo.ancho) y es de color \(rectangulo.color)")

//Devuelve:
//El rectángulo mide 9 x 4 y es de color Azul

Como se aprecia en el ejemplo, la variable rectángulo es una instancia de la clase Rectángulo y si bien la propiedad color pertenece a la súper clase, se utiliza como si hubiera sido definido dentro de la sub clase.

De la misma manera, se pueden crear otras subclases adicionales:

class Circulo:FiguraGeometrica {
    var radio: Double

    init(color: String, radio:Double) {
        self.radio = radio
        super.init(color: color)
    }
}

Una clase puede tener n cantidad de subclases, pero una subclase solo puede tener una súper clase.

Override

En el proceso de override se sobreescriben las funcionalidades de los métodos (lo mismo de las propiedades) para proveer una implementación alternativa en la subclase.

class Rectangulo:FiguraGeometrica {
    let lados = 4
    var alto:Int
    var ancho:Int

    init(color:String, alto:Int, ancho:Int){
        self.alto = alto
        self.ancho = ancho
        super.init(color: color)
    }

    func incrementarAlto() {
        alto += 1
    }

    func incrementarAlto(en valor: Int) {
        alto += valor
    }

    override func calcularArea() {
        area = Double(alto) * Double(ancho)
    }

    override func calcularPerimetro() {
        perimetro = 2 * Double(alto) + 2 * Double(ancho)
    }
}

class Circulo:FiguraGeometrica {
    var radio: Double

    init(color: String, radio:Double) {
        self.radio = radio
        super.init(color: color)
    }

    override func calcularArea() {
        area = Double.pi * radio * radio
    }

    override func calcularPerimetro() {
        perimetro = 2 * Double.pi * radio
    }
}

Tanto la clase Rectangulo como Circulo ahora tienen sus propias implementaciones de los métodos calcularArea() y calcularPerimetro(), los cuales difieren entre sí ya que sus fórmulas son distintas. Para sobreescribir la versión de la súper clase se usa la palabra reservada override.

let circulo = Circulo(color: "verde", radio: 6.43)
circulo.calcularArea()
circulo.calcularPerimetro()
print("El area del círculo es \(circulo.area) y el perimetro es \(circulo.perimetro)")

//Devuelve:
//El area del círculo es 129.888834103405 y el perímetro es 40.4008815251647

Ejemplos completos

class UnaClase {
    
}

class Rectángulo1 {
    let lados = 4
    let alto = 5
    let ancho = 2
}

let figura1 = Rectángulo1()
print("la figura contiene \(figura1.lados) lados")
//Devuelve
//la figura contiene 4 lados

class FiguraGeometrica {
    var color:String
    var area = 0.0
    var perimetro = 0.0
    
    init(color:String) {
        self.color = color
    }
    
    func calcularArea() {
        //No escribimos nada ya que cada figura tiene su propia fórmula
    }
    
    func calcularPerimetro() {
        //No escribimos nada ya que cada figura tiene su propia fórmula
    }
    
    func cambiar(color:String) {
        self.color = color
    }
    
}


class Rectángulo2 {
    let lados = 4
    var alto:Int
    var ancho:Int
    
    init(alto:Int, ancho:Int){
        self.alto = alto
        self.ancho = ancho
    }
    
    func incrementarAlto() {
        alto += 1;
    }
    
    func incrementarAlto(en valor: Int) {
        alto += valor;
    }
}

let figura = Rectángulo2(alto: 3, ancho: 6)
figura.incrementarAlto()
figura.incrementarAlto(en: 6)
print("La figura mide \(figura.ancho) x \(figura.alto)")
//Devuelve:
//La figura mide 6 x 3


/*class subClase: superClase {
    
}
*/


class Rectángulo:FiguraGeometrica {
    let lados = 4
    var alto:Int
    var ancho:Int
    
    init(color:String, alto:Int, ancho:Int){
        self.alto = alto
        self.ancho = ancho
        super.init(color: color)
    }
    
    func incrementarAlto() {
        alto += 1;
    }
    
    func incrementarAlto(en valor: Int) {
        alto += valor;
    }
    
    override func calcularArea() {
        area = Double(alto) * Double(ancho)
    }
    
    override func calcularPerimetro() {
        perimetro = 2 * Double(alto) + 2 * Double(ancho)
    }
}

let rectangulo = Rectángulo(color: "Azul", alto: 9, ancho: 4)
print("El rectángulo mide \(rectangulo.ancho) x \(rectangulo.alto) y es de color \(rectangulo.color)")
//Devuelve:
//El rectángulo mide 4 x 9 y es de color Azul

class Círculo:FiguraGeometrica {
    var radio: Double
    
    init(color: String, radio:Double) {
        self.radio = radio
        super.init(color: color)
    }
    
    override func calcularArea() {
        area = Double.pi * radio * radio
    }
    
    override func calcularPerimetro() {
        perimetro = 2 * Double.pi * radio
    }
}

let círculo = Círculo(color: "verde", radio: 6.43)
círculo.calcularArea()
círculo.calcularPerimetro()
print("El area del círculo es \(círculo.area) y el perímetro es \(círculo.perimetro)")
//Devuelve:
//El area del círculo es 129.888834103405 y el perímetro es 40.4008815251647