web-dev-qa-db-ja.com

グローバルなiPhone例外処理をどのように実装しますか?

NSExceptionをスローするiPhoneアプリケーションで1つのクラッシュがあります。クラッシュレポートは、エラーの場所と正確な原因を完全にあいまいにしています。どこにトップレベルの例外ハンドラを設定して、それが原因であるかを確認するスマートな方法はありますか?私自身で問題を再現することはできませんが、ベータユーザーの一部は確かに再現できます。

この性質の問題を処理するスマートな方法は何ですか?

59
Coocoo4Cocoa

ここで2つの質問をしているようです:トップレベルの例外ハンドラを設定する方法。そして根本原因が何であるかを決定する問題に対処する方法。

例外をキャッチするにはいくつかの方法がありますが、このための最善のアプローチは、NSSetUncaughtExceptionHandlerを使用して例外ハンドラーを設定することです。

アプリで例外が発生すると、デフォルトの例外ハンドラーによって処理されます。このハンドラーは、アプリを閉じる前にコンソールにメッセージを記録するだけです。上記の関数を使用して独自のカスタム例外ハンドラーを設定することにより、これをオーバーライドできます。これを行う最適な場所は、アプリデリゲートapplicationDidFinishLaunching:メソッドです。

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    NSSetUncaughtExceptionHandler(&myExceptionHandler);
}

カスタムハンドラーを設定したら、デフォルトの出力を拡張して、原因を判別できるようにします。

void myExceptionHandler(NSException *exception)
{
    NSArray *stack = [exception callStackReturnAddresses];
    NSLog(@"Stack trace: %@", stack);
}

残念ながら、OSXと比較すると、iPhoneはNiceスタックトレースの生成に関してかなり制限されているように見えます。上記のコードは、一見迷惑な出力を生成します。ただし、この出力はatosツールを使用して実行でき、そこから有用なスタックトレースを生成できるはずです。

別のオプションは、 この記事 の指示に従うことです。これにより、Niceスタックトレースが自動的に生成されます。

これはベータテスターに​​向けて行われているので、あなたはそれを動作させるためにいじくり回さなければならないかもしれません。

問題を自分で再現することはできず、ユーザーのみを再現できたと言います。この場合、Appleからのテクニカルノート:

https://developer.Apple.com/library/content/technotes/tn2151/_index.html

[〜#〜] update [〜#〜]:この投稿には有用な情報が含まれていますが、含まれるリンクの一部は元に戻せません。 this 別の投稿からの情報を使用することをお勧めします。

80
Paul McCabe

自分でそれを行うことを計画している場合は、これらのアプローチのいずれかを使用できます

アプローチ1:

void onUncaughtException(NSException* exception)
{
//save exception details
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  NSSetUncaughtExceptionHandler(&onUncaughtException);
  //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
//Rest of the coding
}

アプローチ2:

void onUncaughtException(NSException* exception)
{

//Save exception details

}

int main(int argc, char *argv[])
{
    @autoreleasepool {

        NSSetUncaughtExceptionHandler(&onUncaughtException);

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([SGGI_AppDelegate class]));
    }
}



-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
      //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
    //Rest of the coding
 }

Approcach3:

int main(int argc, char *argv[])
{
    @autoreleasepool {

        @try {

            return UIApplicationMain(argc, argv, nil, NSStringFromClass([SGGI_AppDelegate class]));
        }
        @catch (NSException *exception) {      
        //Save the exception
        }
        @finally {
        }

    }
}

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
      //Add coding to find if any exception has occurred from saved details if so send it to server or ask user to comment on the issue.
    //Rest of the coding
 }

注意:

  • 私の観点では、クラッシュ時に例外の詳細をサーバーに送信しようとしないでください。彼がアプリを再起動したときに送信します。

  • NSUserDefaultsを使用して例外の詳細を保存する場合は、クラッシュ時にそれを同期化する必要があります。そうしないと、永続化されません。

次のコードスニペットがジョブを実行します。

   - (void)applicationWillTerminate:(UIApplication *)application
   {
       [[NSUserDefaults standardUserDefaults]synchronize];
   }
  • Sqlite dbに保存する場合、クラッシュ時に永続化するために何も呼び出す必要はありません。
12
Durai Amuthan.H

XCodeでは、objc_exception_throwに常にグローバルブレークポイントを設定する必要があります。次に、(通常)実際に例外をスローしようとしているものに関して、はるかに意味のあるスタックトレースを取得します。

それでも、トレース内の独自のコードなしでタイマーコードまたは他の場所で発生する例外を取得できますが、メソッドチェーンを見ると、通常、例外の概要を知ることができます(ターゲットへの通知の送信など)なくなっている)。

NSSetUncaughtExceptionHandler を試しましたか?

2
kperryua

クラッシュレポートを追跡する別のオプションは、Plausible CrashReporter、フィールドからクラッシュレポートを自動的に送信するオープンソースコードです。

CrashReporterDemoもあります。これは、クラッシュレポートの追跡を改善するために、Plausible CrashReporterといくつかのサーバーコードを組み合わせたオープンソースオプションです。 。

最後に、MacDevCrashReporterがあります。これはiOSExceptional.comと類似しているように見えるサービスで、別の回答で提案されています。私はベータ版にサインアップしていないので、私は彼らのサービス条件が何であるか分かりません。深く入り込む前にチェックする価値があります。

2

Crittercism をご覧ください。アプリを使用しているすべてのユーザーに対してこの情報を取得できるという点で、ここで求めている以上のことを行うため、独自のクラッシュを確認できるはずです。

特定のビルドのDYSMをアップロードすることもできます。アップロードすると、Webサイトで自動的にクラッシュが象徴されます。これにより、デバッガーに接続されることなく、最も明確なスタックトレースが提供されます。

また、Objetive-C例外を破るように設定されていることを確認することもできます。 Xcode 4の[ブレークポイント]タブで、C++例外とObj-C例外の両方またはいずれかでブレークするブレークポイント例外を追加できます。これをオンにしないと、スローされる例外のほとんどのスタックトレースは非常に役に立ちません。

幸運を!

2
Mark