如何处理未明确抛出的方法或代码的错误?
将do / catch块包装成一个编译器警告:
"'catch' block is unreachable because no errors are thrown in 'do' block"
来自C#/ JAVA背景,至少可以说这是一个奇怪的事。作为开发人员,我应该能够在do / catch块中保护和包装任何代码块。仅仅因为方法未明确标记为“throw”并不意味着不会发生错误。
答案 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)
我怀疑你想要捕捉未明确标记为“抛出”的错误。
这没有任何意义。 除了明确标有“throws”的错误之外,您无法捕获。 所以,这个警告是有效的。
对于此示例,如果执行,将发生fatal error: Index out of range
。
这是运行时错误,你无法捕捉它。
对于此示例,您应该像这样检查元素大小,而不是执行try-catch错误处理:
答案 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}中使用NSSetUncaughtExceptionHandler
在AppDelegate
函数中。
功能描述:
更改顶级错误处理程序。
设置顶级错误处理 功能,您可以在程序之前执行最后一分钟的记录 终止。
答案 5 :(得分:-2)
你根本做不到。整个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并不意味着用于安全使用,我认为没有任何理由在不处理需要捕获的风险操作时使用它...
进一步了解,请参阅: