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