不抛出的方法的快速错误处理[重复]

Posted

技术标签:

【中文标题】不抛出的方法的快速错误处理[重复]【英文标题】:Swift Error Handling For Methods That Do Not Throw [duplicate] 【发布时间】:2017-06-19 01:42:32 【问题描述】:

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

将其包装为 do / catch 块会导致编译器警告:

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

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

【问题讨论】:

如果没有明确的throw,那么就没有什么可捕获的了。如果没有任何东西被抛出,do/catch 有什么意义? 好吧,仅仅因为一个方法没有明确地“抛出”并不意味着不会发生运行时错误:) 这意味着没有可捕获的错误。您无法捕获无法捕获的运行时错误。 Java 有无法捕获的异常(错误)。斯威夫特也不例外。 @AlexVPerl 这不是一个糟糕的设计决定——运行时的致命错误不应该被捕获,因为它们表示程序员错误(例如访问超出范围的索引集合或强制展开 nil)。你不应该发现这样的错误,你应该修复你的代码,这样它们就不会首先发生。 【参考方案1】:

错误和异常之间是有区别的。 Swift 只处理显式抛出的错误,并且没有处理异常的本机能力。正如其他人所评论的那样,必须抛出错误,并且您无法捕捉未抛出的内容。

相比之下,Objective-C @try-@catch 处理异常,而不是错误。一些 objc 方法可能会导致异常,但不会以任何方式向编译器声明它们。例如文件句柄.write。此类异常更接近于 Java 的 RuntimeException,后者也不需要声明。

在某些情况下,例如文件处理,在 Swift 中干净地处理 异常 会很好,并且可以通过使用 Objective-C 包装器来实现。见http://***.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

【讨论】:

【参考方案2】:

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

这毫无意义。 除了明确标记为“抛出”的错误之外,您无法捕获其他错误。 所以,这个警告是有效的。

对于本例,如果执行,将出现fatal error: Index out of range。 这是运行时错误,您无法捕捉到它。

对于这个例子,你应该像这样检查元素大小,而不是进行 try-catch 错误处理:

【讨论】:

【参考方案3】:

面对从无法抛出的方法抛出的异常。发现这个异常是从 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

其次,将其标头添加到 Bridging Header 文件中。

#import "ObjcTry.h"

并像这样在您的 swift 代码中使用它:

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 中是不可能实现的,因为 Swift 无法处理运行时错误,例如越界、访问冲突或运行时强制解包失败。如果发生任何这些严重的编程错误,您的应用程序将终止。

一些提示:

Q: How to handle EXC_BAD_ACCESS?答:不可能 Q: How to handle failed forced unwrap? A:不可能 Q: How to handle array out of bounds?答:不可能

长话短说:不要在 Swift 中简化错误处理。始终保持安全。

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

【讨论】:

【参考方案5】:

正如其他人提到的,你不应该捕获这些错误,你应该修复它们,但如果你想在程序终止之前执行更多代码,请使用 NSSetUncaughtExceptionHandler in AppDelegate in @ 987654323@函数。

功能说明:

更改***错误处理程序。

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

【讨论】:

【参考方案6】:

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

我的意思是,如果首先没有发生错误,那么捕获错误是没有意义的……我看不出你为什么要这样做,你只会让编译器无缘无故地生气。

如果您使用 if letguard let 语句安全地打开 optional 也是同样的情况

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? 

Simply Do-Catch 并不是为了安全使用,而且我看不出有任何理由在不处理需要捕获的风险操作时使用它......

更多理解请看:

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html

【讨论】:

Swift 或 ios 即使在非风险函数上也可能表现出意外。 swift中没有针对意外行为的预防措施,这是由于不成熟。 lol答案和选的差不多

以上是关于不抛出的方法的快速错误处理[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何找到方法可能抛出的错误类型并在 Swift 中捕获它们 [重复]

如何找出PHP代码块可能抛出的所有错误?

PHP 异常处理 总出现致命错误 无法捕获异常

Hystrix 不抛出 HystrixRuntimeException,而是空消息错误

JDBC 超时不抛出 SQLTimeoutException

处理 node.js 中 require() 模块抛出的错误