繁体   English   中英

停止NSOperationQueue

[英]Stopping an NSOperationQueue

我有一个NSOperationQueue,它可以循环处理从Web服务器导入的数据。 它通过以下设计来实现。

  1. NSURLConnect包装在NSOperation中并添加到队列中

  2. 成功完成下载(使用块)后,来自请求的数据将包装在另一个NSOperation中,该NSOperation将相关数据添加到Core Data。 此操作已添加到队列中。

  3. 在成功完成(使用另一个块)之后(在指定的延迟之后),我调用启动所有方法的方法,然后返回到步骤1。因此,我在x秒后再次调用另一个服务器。

这很好。 我能够从服务器获取数据并处理后台的所有内容。 而且由于这些只是NSOperations,因此我能够将所有内容置于后台,并一次执行多个请求。 这真的很好。

我目前唯一的问题是一旦执行操作,我将无法成功取消操作。

我已经尝试过以下方法:

- (void)flushQueue
{
    self.isFlushingQueue = YES;
    [self.operationQueue cancelAllOperations];
    [self.operationQueue waitUntilAllOperationsAreFinished];
    self.isFlushingQueue = NO;
    NSLog(@"successfully flushed Queue");

}

其中self.isFlushingQueue是一个BOOL,我用于在将任何新操作添加到队列之前进行检查。 这似乎应该起作用,但实际上不起作用。 关于停止我的科学怪人创作有什么想法吗?

编辑(已解决问题,但从另一个角度来看)

我仍然对为什么我无法取消这些操作感到困惑(我很乐意继续尝试可能的解决方案),但是对于如何以稍微不同的方式解决此问题,我有一些见识。 我决定不使用任何取消操作,而等待直到队列结束,我决定仅使用一个包含所有活动连接列表的数据结构(NSMutableDictionary)。 像这样的东西:

self.activeConnections = [NSMutableDictionary dictionaryWithDictionary:@{
                          @"UpdateContacts": @YES,
                          @"UpdateGroups" : @YES}];

然后在将任何操作添加到队列之前,我只是简单地询问该特定呼叫是“开”还是“关”。 我已经对此进行了测试,并且可以成功控制要循环的每个服务器请求。 要关闭所有内容,我可以将所有连接设置为@NO。

该解决方案有两个缺点(必须手动管理其他数据结构,并且每个操作必须重新开始以查看其终止之前是打开还是关闭)。

编辑-追求更准确的解决方案

我删除了所有不相关的代码(注意没有错误处理)。 我发布了两种方法。 第一个是如何创建请求NSOperation的示例,第二个是用于生成完成块的便捷方法。

请注意,类似于第一种方法,完成块生成器由数十个不同的请求调用。

- (void)updateContactsWithOptions:(NSDictionary*)options
{
    //Hard coded for ease of understanding
    NSString *contactsURL = @"api/url";
    NSDictionary *params = @{@"sortBy" : @"LastName"};

    NSMutableURLRequest *request = [self createRequestUsingURLString:contactsURL andParameters:params];

    ConnectionCompleteBlock processBlock = [self blockForImportingDataToEntity:@"Contact"
                                                                 usingSelector:@selector(updateContactsWithOptions:)
                                                                   withOptions:options andParsingSelector:@selector(requestUsesRowsFromData:)];

    BBYConnectionOperation *op = [[BBYConnectionOperation alloc] initWithURLRequest:request
                                                                        andDelegate:self
                                                                 andCompletionBlock:processBlock];

    //This used to check using self.isFlushingQueue
    if ([[self.activeConnections objectForKey:@"UpdateContacts"] isEqualToNumber:@YES]){
        [self.operationQueue addOperation:op];
    }

}

- (ConnectionCompleteBlock) blockForImportingDataToEntity:(NSString*)entityName usingSelector:(SEL)loopSelector withOptions:(NSDictionary*)options andParsingSelector:(SEL)parseSelector
{
    return ^(BOOL success, NSData *connectionData, NSError *error){

        //Pull out variables from options
        BOOL doesLoop = [[options valueForKey:@"doesLoop"] boolValue];
        NSTimeInterval timeInterval = [[options valueForKey:@"interval"] integerValue];

        //Data processed before importing to core data
        NSData *dataToImport = [self performSelector:parseSelector withObject:connectionData];

        BBYImportToCoreDataOperation *importOperation = [[BBYImportToCoreDataOperation alloc] initWithData:dataToImport 
          andContext:self.managedObjectContext 
          andNameOfEntityToImport:entityName];

        [importOperation setCompletionBlock:^ (BOOL success, NSError *error){
             if(success){
                 NSLog(@"Import %@s was successful",entityName);
                 if(doesLoop == YES){
                     dispatch_async(dispatch_get_main_queue(), ^{
                         [self performSelector:loopSelector withObject:options afterDelay:timeInterval];
                     });
                 }
             }
         }];

        [self.operationQueue addOperation:importOperation];

    };
}

取消NSOperation只是一个请求,这是在NSOperation设置的NSOperation NSOperation子类实际操作该请求并取消它的工作。 然后,您需要确保已为isExecutingisFinished等设置了正确的标志。您还需要以符合KVO的方式执行此操作。 只有设置了这些标志后,操作才能完成。

文档并发编程指南->配置并发执行的操作中有一个示例。 尽管我知道此示例可能无法正确解决所有多线程边缘情况。 示例代码LinkedImageFetcher提供了另一个更复杂的示例: QRunLoopOperation

如果您认为自己正确地响应了取消请求,那么您确实需要发布NSOperation子类代码以进一步检查问题。

您可以尝试尝试以下操作,而不是在可以添加更多操作时使用自己的标志

- (void)setSuspended:(BOOL)suspend

NSOperationQueue方法? 在添加新操作之前,请检查队列是否被isSuspended

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM