1

私は NSOperation にやや慣れていません。長時間実行される可能性のあるタスクを含む既存のアプリがあります。このタスクは、Web サービスを介してデータをダウンロードします。特に接続が遅い地方では、タスクが完了するまでに時間がかかる場合があります。ユーザーがダウンロードをキャンセルできるように、または自動的にタイムアウトできるように、このアプリを更新する必要があります。

現在、GCD を使用してダウンロードを実行していますが、GCD 操作をキャンセルすることはできません。データをダウンロードするクラスは変更されず、長時間実行される操作として扱われることが望ましいです。そのオブジェクトの初期化子は Web サービス データを取得し、完了すると戻ります。

NSInvocationOperation を使用するか、NSOperation のサブクラスを使用するかがわかりません。タスクは非常に単純で、操作のキャンセルを許可するだけです。

MBProgressHUD はアクティビティ インジケーターとして使用され、ユーザーがタップして操作をキャンセルできるように使用されるジェスチャ認識機能を備えています。さらに、操作はタイムアウトを提供する必要があります。操作が完了すると、UI が変更されます。

現在の GCD コード:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{
    // long running operation        
    GaugeList *rg = [[GaugeList alloc] initWithStationInfo:[station id] forHistoryInHours:48 inThisFormat:nil]; 

    dispatch_async(dispatch_get_main_queue(), ^{
        UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        GaugeViewController *vc = [sb instantiateViewControllerWithIdentifier:@"GaugeDetailViewController"];
        [vc setRiverGauge:rg];
        [self.navigationController pushViewController:vc animated:YES];
        [hud removeFromSuperview];
    });

迅速な解決策を探していますが、私が見たほとんどの例は非常に長く、大幅なリファクタリングが必要になる場合があります。これに対する解決策を提供する例を誰か指摘できますか? どうも!});

4

1 に答える 1

1

NSInvocationOperationキャンセルには対応しておりません。操作キューで既存のメソッドを実行できるようにするだけです。取り消しが必要な場合は、NSOperationサブクラスを作成する必要があります。ただし、サブクラスの-mainメソッドNSOperation(長時間実行される作業を配置する場所) では、isCancelledプロパティを継続的にチェックして、いつメソッドから戻って操作を終了するかを判断する必要があるため (つまり.フラグを無視しisCancelledてコード-mainを実行し続けると、キャンセルしても効果がありません)。

したがって、本質的にはNSOperation、長時間実行されるバックグラウンド操作が完了したことを通知するために (メイン キューで) メソッドを呼び出すことができるデリゲートを含むサブクラスを作成し、実行時間の長いコード-mainを定期的なチェックで-isCancelled作成する必要があります。キャンセルに迅速に対応してください。

このようなもの:

@protocol MyOperationDelegate <NSObject>
@required
- (void)myOperationDidComplete:(MyOperation *)operation;
@end

@interface MyOperation : NSOperation
@property (nonatomic, assign) id<MyOperationDelegate> delegate
@end

@implementation MyOperation

- (void)main {
    @autoreleasepool {
        // Long running work
        // Regularly check -isCancelled throughout the work, like this:
        if ([self isCancelled]) {
             // Cleanup
             return;
        }
        // At the end of the work
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.delegate myOperationDidComplete:self];
        });
    }
}

@end
于 2014-01-03T20:09:04.087 に答える