首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >停止NSOperationQueue

停止NSOperationQueue
EN

Stack Overflow用户
提问于 2013-02-08 20:35:54
回答 2查看 3.5K关注 0票数 2

我有一个NSOperationQueue,它在循环中处理从web服务器导入数据的工作。它通过以下设计实现了这一点。

  1. NSURLConnect被包装在一个NSOperation中并添加到队列中。
  2. 在成功完成下载(使用块)后,来自请求的数据被包装在另一个NSOperation中,该NSOperation将相关数据添加到核心数据中。此操作将添加到队列中。
  3. 在成功完成时(使用另一个块),(以及在指定的延迟之后),我调用启动它的方法,并返回到步骤1。因此,我在x秒后进行另一个服务器调用。

这个很好用。我能够从服务器获取数据并处理后台的所有内容。因为这些只是NSOperations,所以我能够把所有的东西放在后台,并一次执行多个请求。这个效果真的很好。

目前唯一的问题是,一旦操作开始运行,我就无法成功地取消这些操作。

我试过以下几种方法:

代码语言:javascript
复制
- (void)flushQueue
{
    self.isFlushingQueue = YES;
    [self.operationQueue cancelAllOperations];
    [self.operationQueue waitUntilAllOperationsAreFinished];
    self.isFlushingQueue = NO;
    NSLog(@"successfully flushed Queue");

}

其中self.isFlushingQueue是一个BOOL,在向队列中添加任何新操作之前,我使用它进行检查。这似乎应该有效,但实际上却行不通。有什么办法阻止我的科学怪人的创作吗?

编辑(解决了问题,但从不同的角度来看)

我仍然对我为什么不能取消这些操作感到困惑(我很乐意继续尝试可能的解决方案),但是对于如何以一种稍微不同的方式解决这个问题,我有了片刻的洞察力。我决定只使用一个包含所有活动连接的列表的数据结构( data,NSMutableDictionary),而不是处理取消操作和等待队列结束。就像这样:

代码语言:javascript
复制
self.activeConnections = [NSMutableDictionary dictionaryWithDictionary:@{
                          @"UpdateContacts": @YES,
                          @"UpdateGroups" : @YES}];

然后,在向队列中添加任何操作之前,我只需询问特定的调用是打开还是关闭。我对此进行了测试,并成功地控制了我想要循环的每个服务器请求。要关闭一切,我只需将所有连接设置为“否”。

这个解决方案有几个缺点(必须手动管理一个额外的数据结构,每个操作都必须重新启动,以查看它在终止之前是打开还是关闭)。

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

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

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

代码语言:javascript
复制
- (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];

    };
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-09 15:39:02

取消NSOperation只是一个请求,一个在NSOperation中设置的标志。这取决于您的NSOperation子类实际操作请求和取消它的工作。然后,您需要确保您已经为isExecutingisFinished等设置了正确的标志。您还需要以符合KVO的方式这样做。只有设置了这些标志之后,操作才会完成。

文档Concurrency Programming Guide -> Configuring Operations for Concurrent Execution中有一个示例。虽然我理解此示例可能不能正确地解释所有多线程边缘情况。在示例代码LinkedImageFetcherQRunLoopOperation中提供了另一个更复杂的示例

如果您认为您对取消请求的响应是正确的,那么您确实需要发布您的NSOperation子类代码来进一步检查这个问题。

票数 3
EN

Stack Overflow用户

发布于 2013-02-08 20:47:51

当可以添加更多操作时,您可以尝试使用您自己的标志。

- (void)setSuspended:(BOOL)suspend

方法在NSOperationQueue上?在添加新操作之前,请检查队列是否使用isSuspended挂起

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14780909

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档