NSOperation子类与NSInvocationOperation一起替换GCD操作

时间:2014-01-03 19:40:22

标签: objective-c nsoperation nsoperationqueue nsinvocationoperation

我对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];
    });

我正在寻找一个快速的解决方案,但我见过的大多数例子都很冗长,可能需要进行大量的重构。任何人都可以指出一个提供解决方案的例子吗?谢谢!     });

1 个答案:

答案 0 :(得分: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