2014年2月15日土曜日

[iOS][Objective-C]uncaught exceptionで異常終了時のログを取得する


どうも。

uncaught exceptionで異常終了した際に、
その内容が確認出来ると便利。

まぁ、
Xcodeにつないで実機動作中であれば、
コンソールに多少の情報が出て、
それだけでも解決に至ることも多いですが。

ファイルに出しておけば、
XcodeでRunしていなくても取り出して確認できるし、
NSUserDefaultに保存しておけば、
次回起動時に異常終了があったことも検知することもできる。

実現するには、
NSSetUncaughtExceptionHandler関数にハンドラ関数のアドレスを渡す」

これがちょっと面倒というか、
C言語的なんだけど。

ハンドラ関数を作成して、
そのアドレスを渡してやることで、
例外発生時の動作を定義出来る。

とりあえず、
ファイル保存をするとして。

AppDelegate内に、
下記のような関数を定義しておく。

※関数のプロトタイプも必要です!
(AppDelegateの頭の方にでも書いておけばOK)

// 例外発生時の情報を出力
void uncaughtExceptionHandler(NSException *exception)
{
 
    NSString *exceptionOccur = @"\n***** Uncaught exception occured!*****";
    // 例外の名前
    NSString *exceptionName = [NSString stringWithFormat:@"exception name:%@",
                                                  [exception name]];
    // 例外の理由
    NSString *exceptionReason = [NSString stringWithFormat:@"exception reason:%@",
                                                     [exception reason]];
    // 例外のコールスタック
    NSString *exceptionCallStack = [NSString stringWithFormat:@"exception callStackSymbols:\n%@\n",
                                                       [exception callStackSymbols]];
 
    // ログファイルに書き出す内容
    NSString *exceptionLog = [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n",
                              exceptionOccur, exceptionName, exceptionReason, exceptionCallStack];
 
 
    // デバッグコンソールにも出力
    NSLog(@"\n%@", exceptionLog);
 
 
    NSString *exceptionLogDir = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory,
                                                                     NSUserDomainMask, YES)
                                 objectAtIndex:0];
 
    NSString *exceptionLogPath = [exceptionLogDir
                                  stringByAppendingPathComponent:@"uncaughtException.log"];
 
    NSError *error = nil;
 
    // ファイルに書き込み
    [exceptionLog writeToFile:exceptionLogPath
                   atomically:NO
                     encoding:NSUTF8StringEncoding
                        error:&error];
 
    if (error) {
     
        LOG(@"Cannot write exception log file!!");
    }

        // もしNSUserDefaultsに保存したいならこんな感じ
        //[[NSUserDefaults standardUserDefaults] setValue:exceptionLog 
        //                                                                    forKey:@"exceptionLog"];
}

んで、
AppDelegate.mの、
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
の中で、

// エラー追跡用の機能を追加する。
NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

と書いておけば、
やりたいことが実現出来る。

ログの内容や形式は、
必要に応じて替えればいいです。


それでは。
ちゃお☆


まこぴー。