5

私が取り組んでいるアプリは、アプリケーション サーバーからのローカル データ キャッシュを定期的に更新します (10 件以上のリクエストで、それぞれにかなりの時間がかかります)。現在、UI スレッドをブロックしないように、これらのリクエストを非同期で実行しています。これらのリクエストは、処理してコア データにロードするのに時間がかかるためbeginBackgroundTaskWithExpirationHandlerNSOperationQueue.

すべてのリクエストを操作キューに追加した後、waitUntilAllOperationsAreFinishedすべての操作が完了するまでブロックするために使用します (これはメイン スレッドではありません)。私のプロトタイプで見られる問題は、アプリを実行してすぐにバックグラウンドにすると (ホームボタンを押す)、waitUntilAllOperationsAreFinishedすべての操作が完了した後でもブロックされたままになることです...しかし、アプリを再度開くとすぐに、ハンドラーが終了します。アプリを実行してフォアグラウンドのままにしておくと、すべて正常に終了します。この動作は、実際のアプリでは常に発生するとは限りませんが、以下のコード例では次のように見えます。

#import "ViewController.h"

@interface ViewController ()

@property (assign, nonatomic) UIBackgroundTaskIdentifier task;
@property (strong, nonatomic) NSOperationQueue *queue;

@end

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self performSelectorInBackground:@selector(queueItUp) withObject:nil];
}

- (void)queueItUp {
    UIApplication *application = [UIApplication sharedApplication];

    self.queue = [[NSOperationQueue alloc] init];
    self.task = [application beginBackgroundTaskWithExpirationHandler:^{
        NSLog(@"Took too long!");

        [self.queue cancelAllOperations];
        [application endBackgroundTask:self.task];
        self.task = UIBackgroundTaskInvalid;
    }];

    for (int i = 0; i < 5; i++) {
        [self.queue addOperationWithBlock:^{
            [NSThread sleepForTimeInterval:3];
            NSLog(@"Finished operation.");
        }];
    }


    NSLog(@"Waiting until all operations are finished.");

    [self.queue waitUntilAllOperationsAreFinished];

    [application endBackgroundTask:self.task];
    self.task = UIBackgroundTaskInvalid;

    NSLog(@"All done :)");
}

@end

私は何を間違っていますか?

ありがとう

4

2 に答える 2

4

サンプルコードは、iPhone またはシミュレーターの iOS 6.1 のどの時点でも永久にブロックされません。行にブレークポイントを置く[application endBackgroundTask:self.task];と、毎回ヒットします。

表示されている動作は、アプリケーションにバックグラウンド タスクを終了するように指示した後、バックグラウンドでログを記録しているためです。正確な詳細はわかりませんが、ログはキューに入れられ、アプリケーションがフォアグラウンドに復元されたときにコンソールに出力されます。代わりに、スレッドの実行が中断される場合があります。

NSLog(@"All done");を呼び出す前に を上に移動するendBackgroundTask:と、ログに記録された出力が表示されます。

于 2013-04-02T19:48:20.010 に答える
1

サンプル コードを使用すると、操作は問題なく完了しています。NSLog(@"All done :)");あなたがぶら下がっているのはその上です。キューはまだ存在し、保留中の操作はありませんが、アクティブな実行ループがなくなり、バックグラウンドでメイン スレッドがブロックされている可能性があります。保留中のバックグラウンド操作が完了したため、ブロックされました。再開すると、アプリケーションは中断したところから続行されます。これを行う場合:

    [[self queue] addOperationWithBlock:^{
        NSLog(@"All done :)");
    }];

動作はさらに明白になるはずです。それはあなたがそうするように言っていることを正確にやっています。

キューに入れられた一連の操作があり、 を呼び出しwaitUntilAllOperationsAreFinishedました。それらが終了すると、バックグラウンドでブロックされます。

この一連の操作が終了したときに、何かを実行しようとしているようです。NSOperation は、この種の動作を構築できる依存関係と完了ブロックを持つ機能を提供します。操作をグループ化し、操作のグループが完了したときに実行される完了ブロックまたは操作を設定できます。これの一部は、同時実行プログラミング ガイドで説明されています。

于 2013-04-02T19:12:43.470 に答える