0

アプリを閉じる前にガラスの割れるアニメーションを表示したい。ExceptionHandler を設定することで、アプリを閉じる前に画面のスクリーンショットをキャプチャすることができました

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler); 
    return YES;
}

void uncaughtExceptionHandler(NSException *exception) {

    UIWindow *lastWindow = [[UIApplication sharedApplication].windows lastObject];
    UIGraphicsBeginImageContext(lastWindow.bounds.size);
    [lastWindow.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *pngImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    NSData * data = UIImagePNGRepresentation(pngImage);
}

しかし、ビューに単純な画像を追加することさえできず、次の描画サイクルの前にアプリがクラッシュします。アプリがシャットダウンする前に画面に何かを表示することはできますか?

4

2 に答える 2

3

例外を発生させると、アプリケーションの状態は未定義になります。アプリケーションが実行中に何をしていたのかはわかりません。問題が発生する可能性があることはたくさんありますが (上記のリンクを参照)、ここで焦点を当てるのはデータの破損です。

一部のクラッシュ レポーターは、プログラムの終了直後にネットワーク経由でクラッシュ レポートを送信しようとします。あなたの場合、アプリを実行し続けてメッセージを表示しようとしていますが、これは同じ効果があります。アプリケーションを実行し続けることは、アプリケーション自体のコードの実行を意味し、アプリケーションは破損した可能性のあるユーザー データを自由に書き込もうとします。 .

モデル オブジェクトが更新されてから保存される Core Data ベースのアプリケーションを考えてみましょう。

person.name = name;
person.age = age; // an exception occurs here
person.birthday = birthday;
[context save: NULL];

クラッシュの時点で、管理オブジェクト コンテキストには部分的に更新されたレコードが含まれています。これは、データベースに保存したくないものであることは間違いありません。ただし、キャッチされなかった例外ハンドラーがアプリケーションの実行を継続すると、アプリケーション内のネットワーク接続、タイマー、またはその他の保留中の実行ループ ディスパッチも実行されます。実行ループからディスパッチされたアプリケーション コードのいずれかに -[NSManagedObjectContext save:] への呼び出しが含まれている場合、部分的に更新されたレコードがデータベースに書き込まれ、ユーザーのデータが破損します。

アプリケーションが不明/不確定な状態にある場合に行う最も安全な方法は、単純に終了することです。

于 2013-05-03T16:29:52.770 に答える
1

これが役立つかどうかはわかりませんが、私のアプリでは、次UIAlertViewのように、クラッシュ、例外の種類、その説明、およびスタック トレース (すべてNSSetUncaughtExceptionHandlerメソッドを使用)についてユーザーに説明を表示することができました。

スペイン語のサンプル

次に、アプリを強制終了するか、アプリが不安定な場合でも続行するという推奨オプションを提供します。私の場合、アプリの機能に部分的に影響したため、ほとんどの場合、ユーザーは作業を保存してアプリを安全に閉じることができました。

必要に応じて、回答を編集してここにコードを投稿できます (Xcode プロジェクト フォルダーを検索する必要があるため、投稿していません)。

編集:

AppDelegate デリゲートのメソッドwillFinishLaunchingWithOptionsで、NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);

次に、次のようにハンドラー メソッドを作成します。

static void uncaughtExceptionHandler(NSException *exception)
{
    [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"kDisculpe", nil) message:[NSString stringWithFormat:@"%@ %@%@ %@%@ %@", NSLocalizedString(@"kErrorText", nil), [exception name], NSLocalizedString(@"kErrorDescripcion", nil), [exception reason], NSLocalizedString(@"kErrorTrazaPila", nil), [exception callStackReturnAddresses]] delegate:[[UIApplication sharedApplication] delegate] cancelButtonTitle:NSLocalizedString(@"kContinuar", nil) otherButtonTitles:NSLocalizedString(@"kSalir", nil), nil] show];
    [[NSRunLoop currentRunLoop] run];
}

次に、AlertView のデリゲート メソッドで次のようclickedButtonAtIndexに設定しました。

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if ([[alertView title] isEqualToString:NSLocalizedString(@"kDisculpe", nil)]) {
        switch (buttonIndex) {
            case 0:
                if ([[alertView title] isEqualToString:NSLocalizedString(@"kDisculpe", nil)]) {
                    [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"kAdvertencia", nil) message:NSLocalizedString(@"kAppContinuaraInestable", nil) delegate:[[UIApplication sharedApplication] delegate] cancelButtonTitle:NSLocalizedString(@"kContinuar", nil) otherButtonTitles:nil] show];
                }
                break;
            case 1:
                exit(0);
                break;
        }
    }
}

私が行った唯一の重要なことは、[[NSRunLoop currentRunLoop] run];これがお役に立てば幸いです.

于 2013-05-03T14:40:52.320 に答える