以下を使用して、次の例外ハンドラーを実装しました。
NSSetUncaughtExceptionHandler(&ExceptionHandler)
次に、ハンドラーは以下を使用して handleException を呼び出します。
[[AppContext alloc] init] performSelectorOnMainThread:@selector(handleException:) withObject:exception waitUntilDone:YES];
そのように実装されています:
NSString *message = [NSString stringWithFormat:MSG_UNHANDLED_EXCEPTION_FORMAT, exception.reason, [exception callStackSymbols]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:TITLE_UNHANDLED_EXCEPTION message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
[alert show];
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop);
while (!_quit) {
for (NSString *mode in (__bridge NSArray *)allModes) {
CFRunLoopRunInMode((__bridge CFStringRef)mode, 0.001, false);
}
}
CFRelease(allModes);
これは、次のシナリオを除いてうまく機能します。UIAlertView は引き続き表示されますが、ユーザー インタラクションは使用できなくなります (ユーザーはメッセージをスクロールしたり、[OK] をタップしたりできません)。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
// do long work on another thread...
dispatch_async(dispatch_get_main_queue(), ^(){
// updating the UI so get back on main thread...
// exception occurs in this block (example)...
@throw [NSException exceptionWithName:@"DispatchAsyncToMainThreadException" reason:@"Example" userInfo:nil];
});
注: 私は実稼働コードで実際に例外をスローしているわけではありません。これは純粋に、未処理の例外が生成されている場所を示すためのものです。
メイン キューにディスパッチされたブロック内から例外が発生しているときに、説明する必要があるのは何ですか。