La tradición sugiere que el primer programa en un nuevo lenguaje de desarrollo debería imprimir las palabras "Hola, mundo!" en la pantalla. En Swift, esto se puede hacer con una sola línea de código:
print("Hola, mundo!")Si has escrito código en C o en Objective-C, esta sintaxis debería serte familiar. En Swift, esta línea de código es un programa completo. No necesitas importar una librería para funcionalidad de entrada y salida o manejo de texto. El código escrito en el contexto global es usado como un punto de entrada para la aplicación, entonces no necesitas una función principal o main(), así como tampoco lo es el escribir punto y coma al final de cada sentencia.
Esta guía te da suficiente información para empezar a escribir código en Swift a partir de la muestra del cómo implementar una variedad de tareas de programación. No te preocupes si no entendiste algo, todo lo aquí mencionado está explicado a detalle en el resto del libro.
Se usa let para crear una constante y var para crear una variable. El valor de una constante no necesita saberse a la hora de compilar, pero hay que asignarle un valor exactamente una vez. Esto significa que puedes usar constantes para nombrar un valor que se determina una vez y usarlo en muchos lugares.
var miVariable = 42
miVariable = 50
let miConstante = 42Una constante o variable debería tener el mismo tipo de valor que le quieras asignar. Sin embargo, no necesitas escribirlo explícitamente todo el tiempo. Proveer un valor cuando creas la constante o variable, permite que el compilador deduzca su tipo. En el ejemplo de arriba, el compilador deduce que miVariable es un número entero por que su valor inicial también lo es.
Si el valor inicial no provée suficiente información (o si no hay un valor inicial), especifica el tipo escribiéndolo después de la variable, separado por dos puntos como se ve a continuación.
let enteroImplicito = 70
let dobleImplicito = 70.0
let dobleExplicita: Double = 70Crea una constante con un tipo explícito de
Floaty un valor de4.
Los valores nunca son implícitamente convertidos a otro tipo. Si necesitas convertir un valor a otro tipo, explícitamente haz una instancia del tipo deseado.
let etiqueta: "El ancho es "
let ancho = 94
let etiquetaAncho = etiqueta + String(ancho)Intenta remover la conversión a
Stringde la última línea. ¿Qué error te aparece?
Hay una manera más simple de incluir varios valores en el texto: Escribe el valor entre paréntesis, y escribe una barra invertida (\) antes de estos. Por ejemplo:
let manzanas = 3
let naranjas = 5
let manazanaResumen = "Yo tengo \(manzanas) manzanas."
let frutaResumen = "Yo tengo \(manzanas + naranjas) pedazos de fruta."Usa
\()para incluir un cálculo de coma flotante en un texto y para incluir el nombre de alguien en un saludo.
Crea arreglos y diccionarios usando corchetes ([]) y accede sus elementos escribiendo el índice o llave en corchetes. Una coma se permite después del primer elemento.
var miListaDeCompras = ["bagre", "agua", "tulipanes", "pintura azul"]
miListaDeCompras[1] = "botella de agua"
var profesiones = [
"Malcolm": "Capitán",
"Kaylee": "Mecánico"
]
profesiones["Jayne"] = "Relaciones Públicas"Si la información de tipo puede ser deducida, puedes escribir un arreglo vacío como [] y un diccionario vacío como [:]: Esto podría ocurrir, por ejemplo, cuando creas un nuevo valor para una variable o pasas un de argumento a una función.
miListaDeCompras = []
profesiones = [:]Usa if y switch para crear sentencias condicionales, y usa for-in, for, while, y repeat para hacer un ciclo. Los paréntesis cerrando la condición o ciclo son opcionales, pero las llaves sobre el cuerpo son requeridos.
let puntajesIndividuales = [75, 43, 103, 87, 12]
var puntajeDeEquipo = 0
for puntaje in puntajesIndividuales {
if puntaje > 50 {
puntajeDeEquipo += 3
} else {
puntajeDeEquipo += 1
}
}
print(puntajeDeEquipo)En una sentencia de if, la sentencia condicional debería ser una expresión booleana, lo cual significa que un código como if score { ... } es un error mas no una comparación implícita a cero. Puedes usar if y let juntos para trabajar con valores que podrían estar ausentes. Estos valores se representan como opcionales. Un valor opcional contiene un valor nil (nulo) para representar que un valor esta faltando. Escribe un signo de interrogación (?) después del tipo de valor para marcarlo como opcional.
var textoOpcional: String? = "Hello"
print(textoOpcional == nil)
var nombreOpcional: String? = "John Appleseed"
var saludo = "Hello!"
if let nombre = nombreOpcional {
saludo = "Hello, \(name)"
}Cambia
textoOpcionalanil. ¿Qué saludo se obtiene? Añade una cláusula deelseque asigna otro saludo sinombreOpcionalesnil.
Si el valor opcional es nil, el valor condicional es falso y el código en las llaves se saltea. De lo contrario, el valor opcional es desenvuelto y asignado al constante después de let, lo cual hace al valor desenvuelto disponible dentro del bloque de código.
Otra manera de manejar valores opcionales es proveer un valor predeterminado usando el operador ??. Si el valor opcional está faltando, el valor predeterminado es usado en su lugar.
let apodo: String? = nil
let nombreCompleto: String = "John Appleseed"
let saludoInformal = "Hola \(apodo ?? nombreCompleto)"switch soporta cualquier tipo de datos y una amplia variedad de operaciones de comparación: no están limitados a números enteros y pruebas de igualdad.
let vegetal = "ají rojo"
switch vegetal {
case "apio":
print("Añade unas pasas y prepara un bocado.")
case "pepino", "berro":
print("Eso haría un buen plato.")
case let x where x.hasPrefix("ají")
print("Es un \(x) picante?")
default:
print("Todo sabe bien en sopa.")
}Intenta remover el caso predeterminado (
default:). ¿Que error recibes?
Nota como let puede ser usado en un patron para asignar el valor que emparejó esa parte del patron a un constante.
Después de ejecutar el código dentro del caso que emparejo, el programa sale del sentencia switch. Ejecución no continua al siguiente caso, entonces no hay necesidad de explícitamente cesar (con break) cada caso.
Puedes usar for-in para iterar sobre elementos en un diccionario proveyendo una pareja de nombres que se usara para cada pareja de llave y valor (key-value en inglés). Diccionarios son una colección sin orden, entonces sus llaves y valores son iterados en una orden arbitraria.
let numerosInteresantes = [
"Primo": [2, 3, 5, 7, 11, 13],
"Fibonacci": [1, 1, 2, 3, 5, 8],
"Cuadrado": [1, 4, 9, 16, 25],
]
var masGrande = 0
for (tipo, numeros) in numerosInteresantes {
for numero in numeros {
if numero > masGrande {
masGrande = numero
}
}
}
print(masGrande)”Añade otra variable para registrar que tipo de número era el mas grande, así también como su valor.
Usa while para repetir un bloque de código hasta que una condición cambie. La condición de un ciclo puede estar al final también, asegurando que el ciclo se ejecute una vez a lo mínimo.
var n = 2
while n < 100 {
n = n * 2
}
print(n)
var m = 2
repeat {
m = m * 2
} while m < 100
print(m)Puedes guardar una indice en una ciclo, usando ..< para hacer un rango de índices, o mediante inicialización explicita, condición, e incremento. Estos dos ciclos hacen lo mismo:
var primerCiclo = 0
for i in 0..<4 {
primerCiclo += i
}
print(primerCiclo)
var segundoCiclo = 0
for var i = 0; i < 4; ++i {
segundoCiclo += i
}
print(segundoCiclo)Usa func para declarar una función. Llama una función anexando una lista de argumentos en paréntesis a la nombre de la función. Usa -> para separar los nombres de los parámetros y tipos del tipo de valor de retorno de la función.
func saludar(nombre: String, dia: String) -> String {
return "Hola \(nombre), hoy es \(dia)."
}
saludar("Bob", dia: "Martes")Remueve el parámetro
dia. Añade un parámetro que incluya el almuerzo de hoy en el saludo.
Usa una tupla para hacer un valor compuesta: por ejemplo, para retornar múltiples valores de una función. Los elementos de una tupla se pueden referir por nombre o número.
func calcularEstadisticas(puntajes: [Int]) -> (min: Int, max: Int, sum: Int) {
var min = scores[0]
var max = scores[0]
var sum = 0
for puntaje in puntajes {
if puntaje > max {
max = puntaje
} else if puntaje < min {
min = puntaje
}
sum += puntaje
}
return (min, max, sum)
}
let estadisticas = calcularEstadisticas([5, 3, 100, 3, 9])
print(estadisticas.sum)
print(estadisticas.2)Funciones también pueden tomar una cantidad variada de argumentos, collecionandolos en un arreglo.
func suma(numeros: Int...) -> Int {
var suma = 0
for numero in numeros {
suma += numero
}
return suma
}
suma()
suma(42, 597, 12)Escribe una función que calcula el valor promedio de sus argumentos.
Funciones pueden ser anidados. Funciones anidados tienen acceso a variables que fueron declaradas en la función exterior. Puedes usar funciones anidados para organizar el código en una función que es larga o compleja.
func retornarQuince() -> {
var y = 10
func añadir() {
y += 5
}
añadir()
return y
}
retornarQuince()Funciones son un tipo de primera clase. Esto significa que una función puede retornar otra función como su valor.
func crearIncrementador() -> ((Int) -> (Int)) {
func añadeUno(numero: Int) -> Int {
return 1 + numero
}
return añadeUno
}
var incrementa = crearIncrementador()
incrementa(7)Una función puede tomar otra función como uno de sus argumentos.
func tieneAlgunPareja(lista: [Int], condicion: (Int -> Bool)) -> Bool {
for elemento in lista {
if condicion(elemento) {
return true
}
}
return false
}
func menosQueDiez(numero: Int) -> Bool {
return numero < 10
}
var numeros = [20, 19, 7, 12]
tieneAlgunPareja(numeros, condicion: menosQueDiez)Funciones en verdad son un caso especial de clausuras: bloques de código que pueden ser llamados después. El código en una clausura tiene acceso a cosas como variables y funciones que estaban disponibles en el contexto donde fue creado, aun si la clausura esta siendo ejecutando en otro contexto: ya viste un ejemplo de esto con funciones anidados. Puedes escribir una clausura sin nombre via encerrando código con llaves ({}). Usa in para separar los argumentos y tipo de valor retornado del cuerpo de la función.
numeros.map({ (numero: Int) -> Int in
let resultado = 3 * numero
return resultado
})Vuelve a escribir la clausura para que retorne cero para todo número impar.
Tienes varias opciones para escribir clausuras mas concisamente. Cuando ya se sabe el tipo de clausura, así como una retrollamada para un delegado, puedes omitir el tipo de los parámetros, valor de retorno o ambos. Clausuras de una sola sentencia implícitamente retornan el valor de su única sentencia.
let numerosMapeados = numeros.map({ numero in 3 * numero })
print(numerosMapeados)Puedes referir a parámetros por número envés de su nombre, esta estrategia es especialmente útil en clausuras cortos. Una clausuras pasado como un ultimo argumento puede aparecer inmediatamente después de los paréntesis. Cuando una clausura es el único argumento a una función, puedes omitir los paréntesis completamente.
let numerosOrdenados = numeros.sort { 0$ > $1 }
print(numerosOrdenados)Usa class seguido del nombre de la clase para crear una clase. Una declaración de una propiedad en una clase es escrita de la misma manera que la declaración de una constante o variable, con la excepción de que esta en el contexto de la clase. Declaraciones de métodos y funciones están escritas de la misma manera.
class Figura {
var numeroDeLados = 0
func descripcionSimple() -> String {
return "Una figura con \(numeroDeLados) lados."
}
}Añade una propiedad constante con
lety añade otra propiedad que toma un argumento.
Crea una instancia de una clase poniendo paréntesis después del nombre de la clase. Usa puntos (.) para acceder los propiedades y métodos de la instancia.
var figura = Figura()
figura.numeroDeLados = 7
var descripcionDeFigura = figura.descripcionSimple()A esta version de la clase Figura le esta faltando algo importante: un inicializador para configurar la clase cuando una instancia se crea. Usa init para crear uno.
class FiguraNombrado {
var numeroDeLados: Int = 0
var nombre: String
init(nombre: String) {
self.nombre = nombre
}
func descripcionSimple() -> String {
return "Una figura con \(numeroDeLados) lados."
}
}Nota como self es usado para distinguir la propiedad nombre del argumento al inicializador también llamado nombre. Sus argumentos al inicializador son pasados como una llamada de función cuando creas una instancia de la clase. Toda propiedad necesita un valor asignado, sea en su declaración (como con numeroDeLados) o en el inicializador (como con nombre).
Usa deinit para crear el deinicializador si necesitas hacer operaciones de limpieza cuando el objeto es deallocado.
Subclases incluyen el nombre de su superclase (o clase padre) después del nombre de su clase, separado por un colon. No hay requerimiento para que clases sean el subclase de alguna clase principal, entonces puede incluir o omitir una superclase según tus necesidades.
Métodos en una subclase que redefinen la implementación de la superclase están marcados con override. Redefinir un método por accidente, sin marcar override, es detectado por el compilador como un error. El compilador también detecta métodos con override que en verdad no redefinen ningún método en su superclase.
class Cuadrado: FiguraNombrado {
var anchoDeLado: Double
init(anchoDeLado: Double, nombre: String) {
self.anchoDeLado = anchoDeLado
super.init(nombre: nombre)
numeroDeLados = 4
}
func area() -> Double {
return anchoDeLado * anchoDeLado
}
override func descripcionSimple() -> String {
return "Un cuadrado con \(anchoDeLado) ancho de lados."
}
}
let prueba = Cuadrado(anchoDeLado: 5.2, nombre: "mi cuadrado de prueba")
prueba.area()
prueba.descripcionSimple()Haz otra subclase de
FiguraNombradollamadoCirculoque toma una radio y un nombre como argumentos a su inicializador. Implementa los métodosarea()ydescripcionSimple()en la claseCirculo.
Además de propiedades simples que son guardados, propiedades pueden tener métodos consultores (get) y modificadores (set).
class TrianguloEquilateral: FiguraNombrado {
var anchoDeLado: Double = 0.0
init(anchoDeLado: Double, nombre: String) {
self.anchoDeLado = anchoDeLado
super.init(nombre: nombre)
numeroDeLados = 4
}
var perimetro: Double {
get {
return 3.0 * anchoDeLado
}
set {
anchoDeLado = newValue / 3.0
}
}
override func descripcionSimple() -> String {
return "Un triángulo equilateral con \(anchoDeLado) ancho de lados."
}
}
var triangle = TrianguloEquilateral(anchoDeLado: 3.1, nombre: "un triangulo")
print(triangulo.perimetro)
triangulo.perimetro = 9.9
print(triangulo. anchoDeLado)En el consultor para perimetro, el nuevo valor tiene el nombre implícito de newValue. Puedes proveer un nombre explícito en los paréntesis después de set.
Nota como el inicializador para la clase TrianguloEquilateral tiene tres pasos diferentes:
- Asignar el valor de las propiedades que la subclase declara.
- Llamar el inicializador del superclase.
- Cambiar el valor de propiedades definidos por la superclase. Cualquier trabajo adicional que requiera el uso de métodos, consultores o modificadores, pueden ser usados en este momento.
Si no necesitas calcular el valor de la propiedad, pero aun necesitas proveer código que es ejecutado después de asignar un valor nuevo, usa willSet y didSet.
El código que proveas es ejecutado cuando el valor cambia afuera de un inicializador. Por ejemplo, el siguiente clase asegura que el ancho de los lados de un triángulo siempre sea igual el ancho de su cuadrado.
class TrianguloYCuadrado {
var triangulo: TrianguloEquilateral {
willSet {
cuadrado.anchoDeLado = newValue.anchoDeLado
}
}
var cuadrado: Cuadrado {
willSet {
triangulo.anchoDeLado = newValue.anchoDeLado
}
}
init(tamaño: Double, nombre: String) {
square = Cuadrado(anchoDeLado: tamaño, nombre: nombre)
triangle = TrianguloEquilateral(anchoDeLado: tamaño, nombre: nombre)
}
}
var trianguloYCuadrado = TrianguloYCuadrado(tamaño: 10, nombre: "otra figura de prueba")
print(trianguloYCuadrado.cuadrado.anchoDeLado)
print(trianguloYCuadrado.triangulo.anchoDeLado)
trianguloYCuadrado.cuadrado = Cuadrado(anchoDeLado: 50, nombre: "cuadrado más grande")
print(trianguloYCuadrado.triangulo.anchoDeLado)Cuando trabajes con valores opcionales, puedes escribir ? antes de operaciones como métodos, propiedades, y subíndices. Si el valor antes de ? es nil, todo después del ? es ignorado y el valor de toda la expresión es nil. De lo contrario, el valor opcional es desenvuelto, y todo después del ? actúa en el valor desenvuelto. En ambos casos, el valor de la expresión es un valor opcional.
let cuadradoOpcional: Cuadrado? = Cuadrado(anchoDeLado: 2.5, nombre: "cuadrado opcional")
let anchoDeLado = cuadradoOpcional?.anchoDeLadoUsa enum para crear una enumeración. Como clases y otros tipos nombrados, enumeraciónes pueden tener métodos asociados con ellos.
enum Rango: Int {
case As = 1
case Dos, Tres, Cuatro, Cinco, Seis, Siete, Ocho, Nueve, Diez
case Jota, Reina, Rey
func descripcionSimple() -> String {
switch self {
case .As:
return "as"
case .Jota:
return "jota"
case .Reina:
return "reina"
case .Rey:
return "rey"
default:
return String(self.rawValue)
}
}
}
let as = Rango.As
let asValor = as.rawValue