В приложении одну ошибку нужно надёжно классифицировать программно и одновременно локализованно показать пользователю. Как разделить эти две задачи в модели ошибки Swift?
Для программной классификации используйте отдельный тип ошибки, обычно enum, с машинно значимыми случаями и associated values. Для пользовательского текста добавьте соответствие LocalizedError либо преобразуйте ошибку в сообщение на уровне UI. Логику нельзя строить на сравнении localizedDescription: это текст представления, а не стабильный идентификатор причины.
Базовый протокол Error описывает сам факт ошибки, но не задаёт формат её отображения пользователю. Поэтому в Swift разделены модель ошибки и дополнительные протоколы представления, включая LocalizedError.
Такой подход решает конфликт между двумя требованиями: коду нужны стабильные значения и данные для ветвления, а интерфейсу нужны понятные сообщения, зависящие от языка и контекста.
Если использовать только строки, код начинает распознавать ошибки через сравнение текста. Это хрупко: перевод, изменение формулировки или добавление технических деталей ломает логику обработки.
Если, наоборот, показывать пользователю имя enum-case или техническое описание, сообщение будет непонятным и может раскрыть внутренние детали. Поэтому причина сбоя должна храниться структурированно, а пользовательский текст — формироваться отдельно.
Опишите доменные причины как случаи enum, а параметры, необходимые для диагностики или восстановления, храните в associated values. Для отображения можно реализовать LocalizedError и предоставить errorDescription; при этом обработчик продолжает работать с самим типом ошибки.
В бизнес-логике следует сопоставлять ошибку с типом и случаем, например различать CheckoutError.declined и CheckoutError.unavailable. Поля associated values можно использовать для решения: предложить повторить операцию, попросить выбрать другой способ оплаты или показать ограничение.
LocalizedError не превращает ошибку в строку: он лишь предоставляет стандартный источник описания и дополнительных подсказок. Если доменный слой не должен зависеть от локализации, лучше оставить ему только Error, а в presentation-слое преобразовывать случаи ошибки в локализованные ресурсы.
Плюс реализации LocalizedError — единый стандартный механизм получения описания. Минус — связь модели ошибки с пользовательским языком и UI-контекстом. Отдельное преобразование в presentation-слое лучше разделяет ответственность, но требует явного маппинга для каждого значимого случая.
Платёжный сервис возвращает ошибки declined с кодом банка и unavailable с признаком временности. Вариант со строками прост, но не позволяет надёжно отличить временный сбой от отказа после локализации сообщения. Вариант с LocalizedError удобен для быстрого показа текста, но может связать сетевой или доменный слой с конкретным языком интерфейса.
Оптимальное решение — хранить структурированный CheckoutError в доменном слое, а в UI иметь преобразователь ошибки в локализованный ресурс. Если небольшой компонент не требует строгого разделения слоёв, допустимо реализовать LocalizedError непосредственно на enum. Результат в обоих случаях один: ветвление выполняется по типу и данным ошибки, а текст можно менять независимо.
Можно ли использовать localizedDescription как код ошибки?
Нет. Это представление для человека, которое может зависеть от языка, реализации протокола и контекста. Для ветвления нужно проверять тип ошибки, её case и структурированные значения.
Обязана ли каждая ошибка реализовывать LocalizedError?
Нет. Достаточно соответствия Error; тогда вызывающий код всё равно может обработать ошибку типобезопасно. LocalizedError нужен только там, где ошибка должна предоставить стандартное описание, recovery suggestion или другие пользовательские сведения.
Где лучше выполнять локализацию: в enum ошибки или в UI?
Это зависит от границ слоя. Реализация LocalizedError удобна для небольшого приложения и единообразного доступа к описанию, но связывает модель с пользовательским представлением. В многослойной системе предпочтительнее локализовать в UI: доменная ошибка остаётся независимой от языка, а presentation-слой явно контролирует тексты и контекст показа.