Під час виклику функції, яка задекларована 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
коду ed.
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
}
}
Ви можете мати декілька заяв про вилов, кожен із яких має різний виняток.
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 Prerelease) .