Failable инициализаторы (init?) в Swift позволяют описать ситуацию, когда создание экземпляра типа может завершиться неудачей и вернуть nil. Они часто используются для валидации входных данных или преобразований, которые могут не увенчаться успехом. В failable инициализаторе можно явно вернуть nil, указывая на неудачное создание объекта.
Пример:
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 } }
Таким образом можно предотвращать создание некорректных объектов.
compactMap), это удобно для фильтрации невалидных экземпляров.Вопрос: Чем отличается init? от init! и когда использовать failable инициализатор с implicit unwrapping?
Ответ: init? возвращает опционал (<type?>), и если инициализация не удалась, вернётся nil, что требует безопасной обработки. init! возвращает implicitly unwrapped optional (<type!>), и если инициализация не удалась, также вернётся nil, но использование такого объекта без проверки приведёт к runtime-crash. Используйте init! только если вы точно уверены, что инициализация не может завершиться неудачей в вашем контексте (например, при работе с storyboard в UIKit).
let value = Int("abc") // value будет nil
История
При парсинге JSON вручную применили обычный инициализатор вместо failable. Это привело к созданию "пустых" пользователей, так как валидация не сработала, и приложение не фильтровало невалидные данные.
История
Использование
init!с потенциально невалидными данными привело к крашу приложения после обновления API: формат входных данных изменился, и в момент извлечения объекта возникал runtime exception из-за неявного распаковки nil.
История
При кастомной реализации failable init забыли явно вернуть nil для некоторых сценариев, и в итоге структура инициализировалась со "грязными" полями, что позднее вызвало баги в бизнес-логике.