Swift 2 - попробуйте multi-catch

Я искал немного и не смог ничего найти - даже вопрос на этом сайте - так что теперь я задаюсь вопросом, поддерживает ли Swift 2 блоки с несколькими перехватчиками, как в Java.

Java-Пример:

try {
    someMethod(); // throws ExceptionOne, ExceptionTwo
} catch(ExceptionOne | ExceptionTwo e) {
    handleMyException();
} catch(Exception e2) {
    handleOtherExceptions();
}

В Swift я не смог реализовать подобное решение. Этот вопрос объясняет хороший способ обработки различных ошибок одного ErrorType enum, но мои требования кажутся другими, поскольку моя ошибка инициализируется сообщением, полученным из HTTP-ответа. Это мое перечисление:

enum HTTPError: ErrorType {
    case BAD_REQUEST(message: String)
    case UNAUTHORIZED(message: String)
    case NOT_FOUND
    case INTERNAL_SERVER_ERROR(message: String)
    case NOT_IMPLEMENTED(message: String)

    static func getErrorForStatusCode(statusCode: Int, message: String? = nil) -> HTTPError {
        switch statusCode {
        case 400:
            return HTTPError.BAD_REQUEST(message: message!)
        case 401:
            return HTTPError.UNAUTHORIZED(message: message!)
        case 404:
            return HTTPError.NOT_FOUND
        case 500:
            return HTTPError.INTERNAL_SERVER_ERROR(message: message!)
        case 501:
            return HTTPError.NOT_IMPLEMENTED(message: message!)
        default:
            return HTTPError.INTERNAL_SERVER_ERROR(message: message!)
        }
    }
}

Когда я хочу выдать ошибку этого перечисления, я использую такой код:

func someMethod() throws {
    ...
    HTTPError.getErrorForStatusCode(400, message: "Field X missing") // Actual values coming from HTTP-response
    ...
}

Теперь в вызывающем методе я должен отлавливать каждую ошибку перечисления отдельно, хотя я хочу, чтобы все они делали то же самое (за исключением NOT_FOUND, но это не имеет значения здесь):

try {
    someMethod() // throws
} catch HTTPError.BAD_REQUEST(let message) {
    // display 'message' to user
} catch HTTPError.UNAUTHORIZED(let message) {
    // display 'message' to user
} catch HTTPError.INTERNAL_SERVER_ERROR(let message) {
    // display 'message' to user
}
...

Swift 2 действительно не содержит мульти-улов? Или есть другое решение, которое поможет мне решить мою проблему?

РЕДАКТИРОВАТЬ: Кажется, мое желаемое поведение не совсем ясно: я хочу обрабатывать ошибки типа HTTPError (за исключением HTTPError.NOT_FOUND) таким же образом, поэтому я прошу multi-catch.

Я по-прежнему буду реализовывать общий блок catch, чтобы охватить все ошибки, о которых я не знаю (например, timeout, nil-access, ...), но те ошибки, которые приходят с сообщением backend, должны обрабатываться особым образом.

Спасибо, Чаки

2 ответа

Решение

Swift 2 поддерживает multi-catch

Из документации

Вы пишете шаблон после catch, чтобы указать, какие ошибки может обработать это предложение. Если предложение catch не имеет шаблона, оно сопоставляет любую ошибку и связывает ее с локальной константой с именемerror,

Так что возьми error постоянный и использовать switch заявление.

do {
  try someMethod() // throws
} catch let error as HTTPError {
  switch error  {
  case .NOT_FOUND:
    print("not found")
  case let message: // handle all errors with a message
    print(message)
  }
}

или с catch шаблон

do {
  try someMethod() // throws
} catch HTTPError.NOT_FOUND {
    print("not found")
} catch let message {
    print(message)
}

что также является исчерпывающим, потому что во всех других случаях есть сообщение.

Кроме того, вы - разработчик - должны точно знать количество дел в перечислении, чтобы вы могли надежно их обработать.

Редактировать:

Другое решение состоит в том, чтобы добавить associatedValue собственность внутри enum

  var associatedValue : String {
    switch self {
    case BAD_REQUEST(let value) : return value
    case UNAUTHORIZED(let value) : return value
    case INTERNAL_SERVER_ERROR(let value) : return value
    case NOT_IMPLEMENTED(let value) : return value
    default: return ""
    }
  }

и использовать этот оператор переключения

do {
  try someMethod() // throws
} catch HTTPError.NOT_FOUND {
  print("not found")
} catch let error as HTTPError {
  print(error.associatedValue)
}
enum Error: ErrorType {
    case E1
    case E2
    case E3
}

func foo(e: Error) throws {
    throw e
}

do {
    try foo(Error.E2)
} catch Error.E1 {
    print(Error.E1) // only Error.E1
} catch {
    print("error: ", error) // all other errors
}
/*
error:  E2
*/

Улов с несколькими шаблонами теперь поддерживается в Swift 5.3. Проверьте подробности предложения:https://github.com/apple/swift-evolution/blob/master/proposals/0276-multi-pattern-catch-clauses.md

Другие вопросы по тегам