明示的にスローしないメソッドまたはコードのエラーを処理する方法は?
Do/catchブロックをラップすると、コンパイラの警告が表示されます。
"'catch' block is unreachable because no errors are thrown in 'do' block"
C#/ Javaバックグラウンドから来る)これは控えめに言っても奇妙です。開発者として、私はコードブロックをdo/catchブロックで保護およびラップできるはずです。メソッドが"throw"で明示的にマークされていても、エラーが発生しないというわけではありません。
スローできないメソッドからスローされた例外に直面しました。この例外は、APIのObjective-C部分からスローされたことが判明しました。したがって、objective-cを使用して古いスタイルの方法でそれをキャッチする必要があります。
最初に、initメソッドでいくつかのブロックをとるObjective-Cクラスを作成します-try、catch、そして最後に。
#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"
そして、あなたの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)
Swiftには、範囲外、アクセス違反、実行時の強制アンラップの失敗などの実行時エラーを処理する機能がないため、Swiftでは要求することはできません。アプリケーションは、これらの深刻なプログラミングエラーのいずれかが発生します。
いくつかのポインタ:
一言で言えば、Swiftでエラー処理をショートカットしないでください。常に安全にプレイしてください。
回避策:実行時エラーを絶対にキャッチする必要がある場合は、プロセス境界を使用して保護する必要があります。 別のプログラム/プロセスを実行 し、パイプ、ソケットなどを使用して通信します。
ERRORSとEXCEPTIONSには違いがあります。 Swiftは、明示的にスローされ、EXCEPTIONSを処理するためのネイティブ機能がないエラーのみを処理します。他の人がコメントしているように、ERRORSをスローする必要があり、スローされないものをキャッチできません。
対照的に、Objective-C @ try- @ catchはexceptionsを扱い、errors、。一部のobjcメソッドでは例外が発生する可能性がありますが、コンパイラに対してそれらを宣言しません。例えばFileHandle.write。このような例外は、宣言する必要のないJavaのRuntimeExceptionとより密接に連携しています。
Swiftできれいにexceptionsを処理するのが適切であるファイル処理などのいくつかの状況があり、それは可能ですObjective-Cラッパーを使用する http://stackoverflow.com/questions/34956002/how-to-properly-handle-nsfilehandle-exceptions-in-Swift-2- を参照
ここに再現されたコード:
#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
}
他の人が述べたように、これらのエラーはキャッチしないでください修正する必要があります。ただし、プログラムが終了する前により多くのコードを実行する場合は、NSSetUncaughtExceptionHandler
のAppDelegate
関数でapplicationdidFinishLaunchingWithOptions
を使用します。
関数の説明:
トップレベルのエラーハンドラーを変更します。
プログラムが終了する前に直前のロギングを実行できるトップレベルのエラー処理関数を設定します。