Быстрая обработка ошибок для методов, которые не выбрасывают
Как обрабатывать ошибки для методов или кода, которые явно не выбрасываются?
Обтекание блоком do/catch приводит к предупреждению компилятора:
"'catch' block is unreachable because no errors are thrown in 'do' block"
Исходя из фона С#/JAVA, это, по меньшей мере, странность. Как разработчик, я должен иметь возможность защищать и обертывать любой блок кода в блоке do/catch. Просто потому, что метод явно не помечен как "throw", это не означает, что ошибок не будет.
Ответы
Ответ 1
Я подозреваю, что вы хотите поймать ошибки, которые явно не отмечены "throws".
![введите описание изображения здесь]()
Это не имеет смысла.
Вы не можете поймать, кроме ошибок, которые явно отмечены "throws".
Таким образом, это предупреждение действительно.
В этом примере, если выполняется, будет fatal error: Index out of range
.
Это ошибка времени выполнения, и вы не можете ее поймать.
В этом примере вы должны проверить размер элементов, как это, вместо обработки ошибок try-catch:
![введите описание изображения здесь]()
Ответ 2
То, что вы запрашиваете, невозможно в Swift, поскольку Swift не имеет возможности обрабатывать ошибки времени выполнения, такие как внешние ограничения, нарушения прав доступа или неудачные принудительные развертывания во время выполнения. Ваше приложение прекратится, если произойдет какая-либо из этих серьезных ошибок программирования.
Некоторые указатели:
Короче говоря: не сокращайте обработку ошибок в Swift. Играйте в нее безопасно, всегда.
Временное решение: если вы абсолютно должны улавливать ошибки во время выполнения, вы должны использовать границы процесса для защиты. Запустить другую программу/процесс и обмениваться данными с помощью труб, сокетов и т.д.
Ответ 3
Столкнувшись с исключением, выведенным из метода, который нельзя выбрасывать. Обнаружено, что это исключение было выбрано из objective-c части API. Поэтому вы должны поймать его по-старому, используя objective-c.
Сначала создайте класс objective-c, который принимает несколько блоков в методе init - для try, catch и finally.
#import <Foundation/Foundation.h>
/**
Simple class for catching Objective-c-style exceptions
*/
@interface ObjcTry : NSObject
/**
* Initializeer
*
* @param tryBlock
* @param catchBlock
* @param finallyBlock
*
* @return object
*/
- (_Nonnull id)initWithTry:(nonnull void(^)(void))tryBlock catch:(nonnull void(^)( NSException * _Nonnull exception))catchBlock finally:(nullable void(^)(void))finallyBlock;
@end
В .m файле:
#import "ObjcTry.h"
@implementation ObjcTry
- (_Nonnull id)initWithTry:(nonnull void(^)(void))tryBlock catch:(nonnull void(^)( NSException * _Nonnull exception))catchBlock finally:(nullable void(^)(void))finallyBlock
{
self = [super init];
if (self) {
@try {
tryBlock ? tryBlock() : nil;
}
@catch (NSException *exception) {
catchBlock ? catchBlock(exception) : nil;
}
@finally {
finallyBlock ? finallyBlock() : nil;
}
}
return self;
}
@end
Во-вторых, добавьте свои заголовки в файл заголовка Bridging.
#import "ObjcTry.h"
И используйте его в своем быстром коде:
var list: [MyModel]!
_ = ObjcTry(withTry: {
// this method throws but not marked so, you cannot even catch this kind of exception using swift method.
if let items = NSKeyedUnarchiver.unarchiveObject(with: data) as? [MyModel] {
list = items
}
}, catch: { (exception: NSException) in
print("Could not deserialize models.")
}, finally: nil)
Ответ 4
Существует разница между ОШИБКАМИ и ИСКЛЮЧЕНИЯМИ. Swift имеет дело только с ошибками, явно скрываемыми THROWN и не имеющими собственных возможностей для работы с EXCEPTIONS. Как прокомментировали другие, ОШИБКИ должны быть брошены, и вы не можете поймать то, что не выбрано.
В отличие от Objective-C @try- @catch сделки с исключениями, а не ошибками. Некоторые методы objc могут вызывать исключения, но никоим образом не объявлять их компилятору. например FileHandle.write. Такие исключения более тесно связаны с Java RuntimeException, которые также не нужно объявлять.
Есть такие ситуации, как обработка файлов, где было бы неплохо обрабатывать исключения чисто в Swift, и это возможно с помощью обертки Objective-C. См. fooobar.com/questions/358091/...
Код, воспроизводимый здесь:
#ifndef ExceptionCatcher_h
#define ExceptionCatcher_h
#import <Foundation/Foundation.h>
NS_INLINE NSException * _Nullable tryBlock(void(^_Nonnull tryBlock)(void)) {
@try {
tryBlock();
}
@catch (NSException *exception) {
return exception;
}
return nil;
}
#endif /* ExceptionCatcher_h */
Затем назовем его из Swift:
let exception = tryBlock {
// execute dangerous code, e.g. write to a file handle
filehandle.write(data)
}
if exception != nil {
// deal with exception which is of type NSException
}
Ответ 5
Как уже упоминалось, вы не должны улавливать эти ошибки, вы должны исправить их, но если вы хотите выполнить больше кода до завершения программы, используйте NSSetUncaughtExceptionHandler
в AppDelegate
в applicationdidFinishLaunchingWithOptions
.
Описание функции:
Изменяет обработчик ошибок верхнего уровня.
Устанавливает обработку ошибок верхнего уровня функция, в которой вы можете выполнять регистрацию в последнюю минуту перед программой завершается.
Ответ 6
Вы просто не можете. Весь оператор do-try-catch
или do-catch
предназначен для обнаружения необработанных ошибок и...
Я имею в виду, что нет смысла ловить ошибку, если на первом месте ошибка не возникает... Я не вижу сценария, почему вы хотите это делать, вы просто разобрали компилятор без всякой причины.
Это тот же самый сценарий, если вы безопасно развернете опцию с операторами if let
или guard let
guard let smth = smthOpt?.moreSpecific else { return }
//Compiler gives warning - unused variable smth. You wouldn't declare the variable and then not use it, or you would?
Просто Do-Catch не предназначен для безопасного использования, и я не вижу причин использовать его, когда вы не имеете дело с рискованными операциями, которые нужно поймать...
для дальнейшего понимания, см.:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html