对于不抛出的方法的快速错误处理

时间:2017-02-02 05:03:59

标签: swift error-handling do-catch

如何处理未明确抛出的方法或代码的错误?

将do / catch块包装成一个编译器警告:

"'catch' block is unreachable because no errors are thrown in 'do' block"

来自C#/ JAVA背景,至少可以说这是一个奇怪的事。作为开发人员,我应该能够在do / catch块中保护和包装任何代码块。仅仅因为方法未明确标记为“throw”并不意味着不会发生错误。

6 个答案:

答案 0 :(得分:6)

Swift无法提出要求,因为Swift无法处理运行时错误,例如越界,访问冲突或运行时强制解包失败。如果发生任何严重的编程错误,您的申请将终止。

一些指示:

长话短说:不要在Swift中快速处理错误处理。永远保持安全。

解决方法:如果绝对必须捕获运行时错误,则必须使用进程边界来保护。 Run another program/process并使用管道,套接字等进行通信。

答案 1 :(得分:5)

面对从无法抛出的方法抛出的异常。发现这个异常是从API的objective-c部分抛出的。因此,您应该使用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

其次,将其标题添加到桥接头文件中。

#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)

答案 2 :(得分:4)

我怀疑你想要捕捉未明确标记为“抛出”的错误。

enter image description here

这没有任何意义。 除了明确标有“throws”的错误之外,您无法捕获。 所以,这个警告是有效的。

对于此示例,如果执行,将发生fatal error: Index out of range。 这是运行时错误,你无法捕捉它。

对于此示例,您应该像这样检查元素大小,而不是执行try-catch错误处理:

enter image description here

答案 3 :(得分:3)

ERRORS和EXCEPTIONS之间存在差异。 Swift只处理明确THROWN并且没有处理EXCEPTIONS的本机功能的错误。正如其他人所评论的那样,必须抛出错误而且你无法捕捉到不被抛出的东西。

相比之下,Objective-C @ try- @ catch处理例外,而不是错误。某些objc方法可能会导致异常,但不会以任何方式将它们声明为编译器。例如FileHandle.write。这些异常与Java的RuntimeException更紧密地对齐,后者也不需要声明。

在某些情况下,例如文件处理,在Swift中干净地处理异常会很好,并且可以使用Objective-C包装器。见http://stackoverflow.com/questions/34956002/how-to-properly-handle-nsfilehandle-exceptions-in-swift-2-0

此处转载的代码:

#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
}

答案 4 :(得分:1)

正如其他人提到的,你不应该抓住这些错误,你应该修复它们,但是如果你想在程序终止之前执行更多代码,请在{{1}中使用NSSetUncaughtExceptionHandlerAppDelegate函数中。

功能描述:

  

更改顶级错误处理程序。

     

设置顶级错误处理   功能,您可以在程序之前执行最后一分钟的记录   终止。

答案 5 :(得分:-2)

你根本做不到。整个do-try-catchdo-catch语句用于捕获未处理的错误并... ...

我的意思是如果在第一个地方没有发生错误就没有意义捕获错误......我看不出你为什么要做这样的事情,你只会让编译器生气。

如果您使用if letguard 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