Los inicializadores failable (init?) en Swift permiten describir una situación en la que la creación de una instancia de tipo puede fallar y devolver nil. Se utilizan a menudo para validar datos de entrada o conversiones que pueden no tener éxito. En un inicializador failable, se puede devolver explícitamente nil, indicando una creación fallida del objeto.
Ejemplo:
struct User { let name: String let age: Int init?(name: String, age: Int) { guard !name.isEmpty, age > 0 else { return nil } self.name = name self.age = age } }
De esta manera, se pueden prevenir la creación de objetos incorrectos.
compactMap), esto es conveniente para filtrar instancias no válidas.Pregunta: ¿Cuál es la diferencia entre init? e init! y cuándo utilizar un inicializador failable con desenrollado implícito?
Respuesta: init? devuelve un opcional (<type?>), y si la inicialización falla, devolverá nil, lo que requiere un manejo seguro. init! devuelve un opcional desenrollado implícitamente (<type!>), y si la inicialización falla, también devolverá nil, pero el uso de tal objeto sin verificación causará un runtime-crash. Utiliza init! solo si estás seguro de que la inicialización no puede fallar en tu contexto (por ejemplo, al trabajar con storyboard en UIKit).
let value = Int("abc") // value será nil
Historia
Al analizar JSON manualmente, se utilizó un inicializador normal en lugar de failable. Esto llevó a la creación de "usuarios vacíos", ya que la validación no funcionó y la aplicación no filtró datos no válidos.
Historia
El uso de
init!con datos potencialmente no válidos provocó un crash en la aplicación después de una actualización de API: el formato de los datos de entrada cambió, y al extraer el objeto ocurrió una excepción en tiempo de ejecución debido a la desenrollado implícito de nil.
Historia
En la implementación personalizada de failable init, se olvidó devolver explícitamente nil para ciertos escenarios, y al final la estructura se inicializó con campos "sucios", lo que más tarde causó errores en la lógica del negocio.