Быстрая обработка ошибок для методов, которые не выбрасывают

Как обрабатывать ошибки для методов или кода, которые явно не выбрасываются?

Обтекание блоком 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