Avatar ·

Как выбросить ошибку/исключение с собственным сообщением в Swift (простой способ)?

Всем привет! Я только начал изучать Swift и никак не могу разобраться с обработкой ошибок. В других языках, например в Python, я могу просто написать `raise Exception("Моё сообщение")` и всё. А в Swift что-то всё сложно. Мне нужно, чтобы в определённом месте кода, при выполнении какого-то условия, программа выкидывала ошибку с моим собственным текстом. Например, я проверяю возраст пользователя: ```swift let age = 15 if age < 18 { // тут нужно выбросить ошибку с сообщением "Пользователь несовершеннолетний" } ``` Я читал про `do-catch`, `try`, но везде нужно создавать какие-то свои типы ошибок через `enum`, реализовывать протокол `Error`. Это кажется слишком громоздким для простой ситуации. Неужели нет способа просто сказать "выбрось вот эту строку как ошибку"? Я пробовал писать `throw "Моя ошибка"`, но компилятор ругается, говорит что String не соответствует протоколу Error. Подскажите, пожалуйста, самый простой и короткий способ выбросить ошибку с кастомным сообщением, без создания целых структур и энумов? Мне нужно буквально 2-3 строчки кода для проверки условия. <<>>

Простой способ: создаём кастомную ошибку через enum

Да, в Swift нельзя просто выбросить строку — это не соответствует строгой системе типов. Но есть очень лаконичный способ, который не требует написания десятков строк. Нужно всего лишь объявить один enum с одним кейсом, который содержит строку:

enum MyError: Error {
    case custom(String)
}

// Использование:
let age = 15
if age < 18 {
    throw MyError.custom("Пользователь несовершеннолетний")
}

Это минимально возможная конструкция. Если вам нужно больше разных ошибок — просто добавьте кейсы:

enum AuthError: Error {
    case invalidEmail
    case weakPassword(String)
    case userNotFound
}

// Выброс с сообщением:
throw AuthError.weakPassword("Пароль должен быть длиннее 8 символов")

Как перехватывать и извлекать сообщение

При обработке ошибки вы можете получить сообщение через switch или if case let:

do {
    let age = 15
    if age < 18 {
        throw MyError.custom("Пользователь несовершеннолетний")
    }
} catch MyError.custom(let message) {
    print("Ошибка: \(message)") // Выведет: Ошибка: Пользователь несовершеннолетний
} catch {
    print("Другая ошибка: \(error)")
}

Ещё более короткий вариант (для продвинутых)

Если вы совсем не хотите объявлять enum, можно использовать структуру с протоколом LocalizedError:

struct SimpleError: LocalizedError {
    let message: String
    var errorDescription: String? { message }
}

// Использование:
throw SimpleError(message: "Что-то пошло не так")

// Перехват:
catch let error as SimpleError {
    print(error.message) // или error.localizedDescription
}

Важные моменты

  • Всегда используйте do-catch — если не обработать throwing функцию, код не скомпилируется (кроме случаев с try!, но это опасно).
  • Enum с associated value — это идиоматичный Swift-способ. Он даёт автодополнение и безопасность типов.
  • Не используйте строки как ошибки — в крупных проектах это усложняет отладку. Лучше создать отдельный enum для каждого модуля.

Таким образом, самый простой способ — это однострочный enum. Он занимает 2 строки в объявлении и 1 строку при выбросе. Это стандартная практика в Swift-сообществе.

<<>>

Альтернатива: использование NSError (для совместимости с Objective-C)

Если вам нужно быстро прототипировать или работать с legacy кодом, можно использовать NSError — он уже реализует протокол Error:

throw NSError(domain: "com.example.app", 
              code: 1001, 
              userInfo: [NSLocalizedDescriptionKey: "Моё кастомное сообщение"])

Преимущества:

  • Не нужно объявлять собственный тип
  • Работает с Objective-C API
Недостатки:
  • Громоздкая запись (много параметров)
  • Нет проверки типов на этапе компиляции
  • Сложнее отлавливать конкретные ошибки

Для простых проверок это может быть быстрее, чем создавать enum, но для production-кода лучше использовать кастомные типы. Если вам нужно выбросить ошибку буквально в 2-3 местах — NSError подойдёт, но не злоупотребляйте им.