Swift 2.0: Error Handling (Обработка ошибок)

В Swift 2.0 наконец добавили обработку ошибок. Для представления ошибок добавили протокол ErrorType.
В основном для создания своих ошибок создают перечисление реализующее этот протокол

При чтении файла допустим мы будем обрабатывать 2 ситуации, пустой путь и отстутствие прав на чтение (needUser будет указывать учетную запись владельца файла)

Чтобы обозначить, что функция/метод могут выбрасывать ошибки наружу — ввели ключевое слово throws, его нужно ставить после круглых скобок функции/метода, но перед возвращаемым типом (если имеется)
Генерация ошибки же происходит с помощью ключевого слова throw

Вызов функции/метода генерирующих ошибки обязана предварять команда try

Если throws функция/метод вызываются из другой функции/метод, то она либо должна так же быть помечена как throws, либо обработать ошибки

Если мы уберем слово throws из определения функции

то получим ошибку в момент вызова readFile, т.к. readFiles теперь сама не может генерировать ошибки наружу, но вызывает функцию генерирующую ошибки и не обрабатывает их

Catching and Handling Errors (Ловля и обработка ошибок)

Чтобы обработать ошибки нужно воспользоваться оператором do-catch

Перепишем код так

1,5 — мы сделали readFiles обычной функцией, не throws
2 — мы выведем в консоль содержимое файла только в том случае если readFile не сгенерировал ошибку
3 — обработка конкретной ошибки
4 — на момент написания статьи Swift 2.0 был в бете, возможно поэтому, хоть мы и перечислили все возможные ошибки которые мы генерируем — компилятор потребовал ввести дополнительно обработку всех возможных ошибок, т.к. посчитал что мы не покрыли все варианты.

Если же мы считаем, что генерация ошибки в конкретной функции должна вызывать падение программы, вместо try используем try!

Specifying Clean-Up Action (Определение действий по очистке)

После отработки кода в функции иногда нужно освободить память, использованные файловые/сетевые дескрипторы. Но при генерации ошибок — мы можем выйти из функции в любой момент, не дублировать же очистку на всех генерациях ошибок.
Взять тот же C#, там после отработки всех обработчиков catch можно использовать команду finally {}, код внутри которой будет выполнен вне зависимости от того вылетела ошибка или нет. Все бы хорошо, но код освобождения памяти/ресурсов внутри finally местами начинает дублировать код самого метода, т.к. мы не знаем внутри finally на каком месте была прервано выполнение, если оно было прервано. Нужно ли освобождать этот дескриптор или ошибка была раньше и он пока равен null, окей сделаем проверку и т.д.
В swift поступили хитрее. По всему коду мы раскидываем куски кода с использованием команды defer {} код внутри которой будет выполнен после выполнения всего кода функции/метода. Таким образом мы прям в коде наглядно освобождаем нужные ресурсы.

Если выполним с нулевым путем — нас ждет в консоли просто необработанная ошибка unexpected error thrown, т.к. defer так и не был выполнен, throw FileReadError.EmptyName отработал раньше.

А если путь будет задан, defer пометит себя активным и будет ждать окончания выполнения функции readFile, и независимо от того была она завершена корректно или с ошибкой — после отработки всех команд — выполнится. Если по ходу выполнения кода было несколько defer — первым выполнится тот, который пометил себя последним и так до самого первого defer в коде функции.
Так что в этом случае выведется

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *