不抛出的方法的快速错误处理[重复]
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-catch
或do-catch
语句旨在用于捕获未处理的错误和...
我的意思是,如果首先没有发生错误,那么捕获错误是没有意义的……我看不出你为什么要这样做,你只会让编译器无缘无故地生气。
如果您使用 if let
或 guard 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 中捕获它们 [重复]
Hystrix 不抛出 HystrixRuntimeException,而是空消息错误