При вызове функции, объявленной throws
в Swift, вы должны аннотировать сайт вызова функции с помощью try
или try!
. Например, учитывая функцию броска:
func willOnlyThrowIfTrue(value: Bool) throws {
if value { throw someError }
}
эта функция может быть вызвана так:
func foo(value: Bool) throws {
try willOnlyThrowIfTrue(value)
}
Здесь мы аннотируем вызов с try
, который вызывает читателя, что эта функция может вызвать исключение, и любые последующие строки кода могут не выполняться. Мы также должны пометить эту функцию с помощью throws
, потому что эта функция может генерировать исключение (то есть, когда willOnlyThrowIfTrue()
выбрасывает, то foo
автоматически сбросит исключение вверх.
Если вы хотите вызвать функцию, которая объявлена как возможно сгенерированная, но которую вы знаете, не сгенерирует в вашем случае, потому что вы даете ей правильный ввод, вы можете использовать try!
.
func bar() {
try! willOnlyThrowIfTrue(false)
}
Таким образом, когда вы гарантируете, что код не сработает, вам не нужно вводить дополнительный шаблонный код, чтобы отключить распространение исключений.
try!
принудительно выполняется во время выполнения: если вы используете try!
и функция в конечном итоге выбрасывает, то выполнение вашей программы будет прервано с ошибкой во время выполнения.
Большая часть кода обработки исключений должна выглядеть следующим образом: либо вы просто распространяете исключения вверх, когда они возникают, либо вы устанавливаете условия так, чтобы исключить возможные исключения. Любая очистка других ресурсов в вашем коде должна происходить с помощью уничтожения объекта (т.е. deinit()
) или иногда с помощью defer
редактируемого кода.
func baz(value: Bool) throws {
var filePath = NSBundle.mainBundle().pathForResource("theFile", ofType:"txt")
var data = NSData(contentsOfFile:filePath)
try willOnlyThrowIfTrue(value)
// data and filePath automatically cleaned up, even when an exception occurs.
}
Если по какой-либо причине у вас есть код для очистки, который должен быть запущен, но отсутствует в deinit()
функции, вы можете использовать defer
.
func qux(value: Bool) throws {
defer {
print("this code runs when the function exits, even when it exits by an exception")
}
try willOnlyThrowIfTrue(value)
}
Большая часть кода, который имеет дело с исключениями, просто передает их вызывающим абонентам, делая очистку по пути через deinit()
или defer
. Это потому, что большая часть кода не знает, что делать с ошибками; он знает, что пошло не так, но у него недостаточно информации о том, что пытается сделать какой-то код более высокого уровня, чтобы узнать, что делать с ошибкой. Он не знает, подходит ли представление диалога пользователю, следует ли повторить попытку, или что-то еще подходит.
Однако код более высокого уровня должен точно знать, что делать в случае любой ошибки. Таким образом, исключения позволяют конкретным ошибкам всплывать от того места, где они изначально возникли, до места, где они могут быть обработаны.
Обработка исключений осуществляется с помощью catch
операторов.
func quux(value: Bool) {
do {
try willOnlyThrowIfTrue(value)
} catch {
// handle error
}
}
Вы можете иметь несколько операторов catch, каждый из которых перехватывает свое исключение.
do {
try someFunctionThatThowsDifferentExceptions()
} catch MyErrorType.errorA {
// handle errorA
} catch MyErrorType.errorB {
// handle errorB
} catch {
// handle other errors
}
Для получения дополнительной информации о передовых практиках с исключениями см. Http://exceptionsafecode.com/ . Он специально нацелен на C ++, но после изучения модели исключений Swift, я думаю, что основы применимы и к Swift.
Подробнее о синтаксисе Swift и модели обработки ошибок см. Книгу «Язык программирования Swift (предварительный выпуск Swift 2)» .