ある段階で一連の行を追加または削除する UITableView を使用して iOS アプリを開発しています。行数が多いため、この操作には時間がかかる場合があります。ただし、時間がかかるかどうかは簡単には判断できません。
この操作に時間がかかる場合にのみ、UIActivityIndicator (スピナー) を表示したいと考えています。私がいつもこれを行ってきた方法は、時間のかかる操作を開始し、ある程度の遅延 (0.5 秒など) の後、操作がまだ実行されているかどうかをテストし、実行されている場合は、UIActivityIndicator の表示を開始します。
時間のかかる操作をバックグラウンド スレッドで実行できる場合、これは問題ありません。ただし、この特定のケースは注意が必要です。これは、長い操作 (deleteRowsAtIndexPaths:withRowAnimation:) をメイン スレッドで実行する必要があるためです (このメソッドをバックグラウンド スレッドで実行すると、バックグラウンド スレッドが UI を更新しようとすると、アプリがクラッシュすることがあります)。
私が試した最新のことは、次の行にありました。
- (void) manipulateTableView
{
stillBusy = YES;
[self performSelectorInBackground:@selector(waitBeforeShowingBusyIndicatorForView:) withObject:view];
.
.
.
[self performSelectorOnMainThread:@selector(deleteRowsAtIndexPathsWithRowAnimation:) withObject:args waitUntilDone:YES];
stillBusy = NO;
}
- (void) waitBeforeShowingBusyIndicatorForView:(UIView*) view
{
usleep((int) (BUSY_INDICATOR_DELAY * 1000000));
if (stillBusy)
[self performSelectorOnMainThread:@selector(showBusyIndicatorForView:) withObject:view waitUntilDone:NO];
}
showBusyIndicatorForView: は UI を操作するため、メイン スレッドで呼び出す必要があります。そうしないと、アプリがクラッシュする可能性があります。
deleteRowsAtIndexPaths:withRowAnimation: に非常に長い時間がかかる場合、waitBeforeShowingBusyIndicatorForView: の遅延が期限切れになり、performSelectorOnMainThread:... メソッドが呼び出されてすぐに戻ります。しかし、その後 showBusyIndicatorForView: メソッドが呼び出されるのは、deleteRowsAtIndexPaths:withRowAnimation: への呼び出しが完了した後であるため、目的に反します。
なぜこれが起こるのか理解できたと思います。deleteRowsAtIndexPaths:withRowAnimation: メソッドはメイン ループの繰り返しで実行され、実行中は showBusyIndicatorForView: の呼び出しがメイン ループのメッセージとしてキューに入れられます。メイン ループが deleteRowsAtIndexPaths:withRowsAnimation: の実行を完了した後でのみ、次のメッセージのキューをポーリングし、showBusyIndicatorForView: の実行を開始します。
これを適切に機能させる方法はありますか。メインループを中断して、すぐに showBusyIndicatorForView: を実行させることは可能でしょうか?