Programación · Lenguajes de programación
Tutorial de Swift para principiantes
Respuesta corta
Swift es un lenguaje rápido, seguro y compilado creado por Apple para aplicaciones de iPhone, iPad, Mac, Apple Watch y Apple TV, y que también funciona en Linux y Windows. Guarda print("Hello, world") en hello.swift y ejecuta swift hello.swift. Las ideas centrales son las constantes con let y las variables con var, la inferencia de tipos, los opcionales para valores que pueden faltar, los structs y enums con semántica de valor, los protocolos y los errores tratados con do/try/catch.
Qué es Swift y para qué se usa
Swift fue presentado por Apple en 2014 como sustituto moderno de Objective-C y se publicó como código abierto en 2015; el proyecto está en swift.org. Es el lenguaje principal de las aplicaciones en plataformas Apple, normalmente con los frameworks SwiftUI o UIKit. Swift también se usa para código del lado del servidor (por ejemplo con el framework Vapor) y herramientas de línea de comandos. El lenguaje está diseñado para evitar errores comunes: las variables deben inicializarse, los arrays comprueban sus límites y nil debe tratarse de forma explícita.
Instalar Swift y ejecutar Hello, world
En un Mac, instala Xcode desde la App Store o las herramientas de línea de comandos de Xcode. En Linux y Windows, descarga una toolchain desde swift.org. Compruébalo con swift --version.
print("Hello, world")swift hello.swift
# Hello, world
swiftc hello.swift -o hello # compile to a binary
./helloPara un proyecto más grande, ejecuta swift package init --type executable y después swift run. Los playgrounds de Xcode son otra forma fácil de experimentar.
Constantes, variables y tipos básicos
Usa let para constantes y var para variables. Prefiere let; el compilador avisa cuando un var no se modifica nunca. Los tipos se infieren, y Swift nunca convierte implícitamente entre tipos numéricos.
| Tipo | Ejemplo | Notas |
|---|---|---|
Int | let n = 42 | 64 bits en las plataformas modernas |
Double | let x = 3.14 | Tipo de coma flotante por defecto |
Bool | let ok = true | true o false |
String | let s = "hi \(name)" | Texto Unicode, tipo de valor |
Character | let c: Character = "é" | Un carácter tal como lo percibe el usuario |
[Int], [String: Int] | [1, 2], ["a": 1] | Array y diccionario |
let name = "Ada"
var count = 7
count += 1
let avg = Double(count) / 2 // explicit conversion
print("\(name) has \(count) items, avg \(avg)") // Ada has 8 items, avg 4.0
print(7 / 2, 7 % 2) // 3 1\(expression) dentro de un literal de cadena inserta un valor (interpolación de cadenas).
Control de flujo
let score = 72
if score >= 90 {
print("A")
} else if score >= 70 {
print("B") // B
} else {
print("C")
}
for i in 0..<3 {
print(i, terminator: " ") // 0 1 2
}
print()
var n = 10
while n > 1 { n /= 2 }
print(n) // 1
let day = "SAT"
switch day {
case "SAT", "SUN":
print("weekend") // weekend
default:
print("weekday")
}switch debe ser exhaustivo, no continúa en la siguiente rama por defecto y puede hacer coincidir rangos (case 90...100:), tuplas y casos de enum.
Funciones y closures
Los parámetros tienen etiquetas de argumento que escribe quien llama, lo que hace que las llamadas se lean como frases. Usa _ para omitir una etiqueta. Los closures son funciones anónimas escritas entre llaves.
func greet(_ name: String, with greeting: String = "Hello") -> String {
return "\(greeting), \(name)!"
}
print(greet("Lin")) // Hello, Lin!
print(greet("Lin", with: "Hi")) // Hi, Lin!
let nums = [3, 1, 2, 5]
let squares = nums.map { $0 * $0 }
let evens = nums.filter { $0 % 2 == 0 }
let sorted = nums.sorted(by: >)
print(squares, evens, sorted) // [9, 1, 4, 25] [2] [5, 3, 2, 1]$0 se refiere al primer argumento del closure. Cuando un closure es el último argumento, puede escribirse después de los paréntesis (sintaxis de trailing closure).
Arrays, diccionarios y conjuntos
var fruits = ["apple", "pear"]
fruits.append("fig")
print(fruits.count, fruits[0], fruits.contains("fig")) // 3 apple true
var ages: [String: Int] = ["ann": 31, "bob": 25]
ages["cy"] = 40
for (person, age) in ages.sorted(by: { $0.key < $1.key }) {
print(person, age) // ann 31, bob 25, cy 40
}
print(ages["zed", default: 0]) // 0
let tags: Set = ["b", "a", "b"]
print(tags.count) // 2Las colecciones son tipos de valor: asignar un array a otra variable crea una copia independiente (copiada de forma diferida, solo cuando una de ellas cambia). Un array declarado con let no puede modificarse en absoluto.
Característica distintiva: los opcionales
Un valor que puede faltar tiene un tipo opcional, que se escribe String?. No puedes usarlo como String hasta que lo desenvuelves, así que el compilador te obliga a tratar el caso nil.
let input = "42"
let number: Int? = Int(input) // nil if input is not a number
if let number { // unwrap: runs only when not nil
print("got \(number)") // got 42
}
func firstWord(_ text: String) -> String? {
text.split(separator: " ").first.map(String.init)
}
guard let word = firstWord("hello world") else {
fatalError("no words")
}
print(word) // hello
print(firstWord("")?.uppercased() ?? "none") // noneif let y guard let desenvuelven de forma segura, ?. (encadenamiento opcional) llama a un método solo cuando el valor existe, y ?? proporciona un valor por defecto. El desenvolvimiento forzado value! falla cuando el valor es nil, así que úsalo poco. La forma corta if let number requiere Swift 5.7 o posterior.
Structs, clases, enums y protocolos
Los structs y enums son tipos de valor; las clases son tipos de referencia con herencia. El código Swift prefiere los structs y los protocolos (interfaces) a las jerarquías de clases.
protocol Shape {
func area() -> Double
}
struct Rect: Shape {
var width: Double
var height: Double
func area() -> Double { width * height }
}
enum Circle: Shape {
case unit
case radius(Double)
func area() -> Double {
switch self {
case .unit: return Double.pi
case .radius(let r): return Double.pi * r * r
}
}
}
let shapes: [any Shape] = [Rect(width: 2, height: 3), Circle.radius(1)]
let total = shapes.reduce(0) { $0 + $1.area() }
print((total * 100).rounded() / 100) // 9.14Los structs reciben automáticamente un inicializador memberwise (Rect(width:height:)). Los casos de un enum pueden llevar valores asociados, como hace .radius(Double).
Manejo de errores
Las funciones que pueden fallar se marcan con throws. Quien las llama debe usar try dentro de un bloque do/catch, o usar try? para convertir un error en nil.
enum AgeError: Error {
case notANumber(String)
case negative
}
func parseAge(_ text: String) throws -> Int {
guard let age = Int(text) else { throw AgeError.notANumber(text) }
guard age >= 0 else { throw AgeError.negative }
return age
}
do {
print(try parseAge("41")) // 41
print(try parseAge("abc"))
} catch AgeError.notANumber(let text) {
print("not a number: \(text)") // not a number: abc
} catch {
print("other error: \(error)")
}
let maybe = try? parseAge("-3") // nil
print(maybe as Any) // nilUn programa completo pequeño: frecuencia de palabras
import Foundation
let args = CommandLine.arguments
guard args.count == 2 else {
print("usage: swift words.swift FILE")
exit(1)
}
do {
let text = try String(contentsOfFile: args[1], encoding: .utf8).lowercased()
let words = text.split { !$0.isLetter && $0 != "'" }
var counts: [Substring: Int] = [:]
for word in words {
counts[word, default: 0] += 1
}
for (word, n) in counts.sorted(by: { $0.value > $1.value }).prefix(5) {
print(String(n).padding(toLength: 6, withPad: " ", startingAt: 0) + word)
}
} catch {
print("cannot read \(args[1]): \(error.localizedDescription)")
exit(1)
}Ejecútalo con swift words.swift notes.txt. Foundation ofrece lectura de archivos y utilidades para cadenas; está disponible en las plataformas Apple y en las toolchains de Linux y Windows.
Errores comunes de principiantes
- Intentar cambiar una constante
leto una propiedad de un struct declarado conlet. Usavarcuando el valor deba cambiar. - Esperar que un struct se comparta como un objeto. Cambiar una copia no cambia el original; usa una clase si necesitas identidad compartida.
- Indexar un
Stringcon un entero, comos[0]. Usas.first,s.prefix(3)o valores deString.Index. - Mezclar
IntyDoubleen una operación aritmética sin convertir, lo que es un error de compilación. - Olvidar
tryantes de una llamada que lanza errores, o usartry!, que falla ante un error.
Adónde ir después
Lee «The Swift Programming Language» en docs.swift.org, la guía y referencia oficial, y el centro de documentación de swift.org. Para aplicaciones, sigue los tutoriales de SwiftUI de Apple en Xcode. Después aprende la concurrencia de Swift (async/await y actores), los genéricos y el Swift Package Manager para las dependencias.
Preguntas frecuentes
¿Swift es solo para plataformas Apple?
No. Swift es de código abierto y también funciona en Linux y Windows, y se usa para código del lado del servidor y herramientas. Sin embargo, los frameworks de aplicaciones como SwiftUI y UIKit son exclusivos de Apple.
¿Debo aprender Swift u Objective-C?
Aprende Swift. Es el lenguaje que Apple recomienda para las aplicaciones nuevas, y puede llamar a código Objective-C existente cuando haga falta.
¿Cuál es la diferencia entre un struct y una clase en Swift?
Un struct es un tipo de valor que se copia al asignarlo o pasarlo; una clase es un tipo de referencia, de modo que todas las variables comparten una sola instancia. Las clases también admiten herencia y deinicializadores.
¿Qué significa el signo de interrogación después de un tipo?
Int? es un opcional: contiene un Int o nil. Debes desenvolverlo, por ejemplo con if let, antes de usar el valor.