Un optional es un tipo que envuelve otro añadiendo la posibilidad de ausencia. String? significa «un String o ningún valor». Bajo el capó es el enum Optional<Wrapped> con casos .some y .none:
var nombre: String? = "Ana"
nombre = nil // válido
var apellido: String = "García"
// apellido = nil // Error de compilación
// El compilador impide usar el optional sin desenvolver
// print(nombre.uppercased()) // Error: value of optional type must be unwrapped
if let y guard let
func saluda(nombre: String?) {
// guard let: salida temprana si nil
guard let n = nombre else {
print("Sin nombre")
return
}
print("Hola, (n)")
}
saluda(nombre: "Pedro") // Hola, Pedro
saluda(nombre: nil) // Sin nombre
// Swift 5.7+: shorthand (misma etiqueta)
if let nombre {
print(nombre) // desenvuelto, tipo String
}
Nil-coalescing ??
Proporciona un valor por defecto cuando el optional es nil. Se puede encadenar para múltiples fuentes:
let entrada: String? = nil
let nombre = entrada ?? "Invitado"
print(nombre) // Invitado
// Encadenado
let a: Int? = nil
let b: Int? = nil
let c = a ?? b ?? 0 // 0
Optional chaining con ?.
struct Direccion { var ciudad: String }
struct Usuario { var direccion: Direccion? }
let u: Usuario? = Usuario(direccion: Direccion(ciudad: "Bilbao"))
print(u?.direccion?.ciudad ?? "") // Bilbao
let fantasma: Usuario? = nil
print(fantasma?.direccion?.ciudad ?? "") //
// Llamar métodos opcionales
let s: String? = "hola"
print(s?.uppercased() ?? "") // HOLA
Cuándo usar forced unwrap
El operador ! fuerza el desenvolvimiento sin comprobar nil; si lo es, el programa se detiene con un error fatal. Úsalo solo cuando tengas certeza absoluta de que el valor existe y no puedas usar if let ni guard let. En código de producción, el forced unwrap es casi siempre evitable y preferiblemente se sustituye por guard let:
let valor: Int? = 42
print(valor!) // 42
// Pattern más seguro
guard let v = valor else { fatalError("valor nulo") }
print(v) // 42
