【问题标题】:How can I know when nsoperation queue has completed all requests so that I can reload my tableview?我如何知道 nsoperation queue 何时完成所有请求以便我可以重新加载我的 tableview?
【发布时间】:2012-08-11 04:50:40
【问题描述】:

我正在使用 ASIHTTPRequest 和 NSOperationQueue 从不同的链接下载数据到

在后台线程中下载。当请求完成时,我使用 requestFinished 进行解析

ASIHTTPRequest 的委托方法。当所有请求都进入时,我想更新 tableview 中的数据

队列已完成。有什么方法可以知道 NSOperationQueue 什么时候处理完所有的

请求?我的意思是队列有任何变量,如“isEmpty”或任何委托方法,如“queueDidCompletedAllOperation”?

请帮忙。

代码如下:

//source

@interface SourceModel : NSObject

@property (nonatomic, retain) NSString * link;

@property (nonatomic, retain) NSString * name;

@end


//for rssGroup

@interface CompleteRSSDataModel : NSObject

@property (nonatomic,strong) SourceModel * source;

@property (nonatomic,strong) KissXMLParser * parser;

@property (nonatomic,strong) NSArray * rssArticles;

@end

- (void)viewDidLoad
{
       for (int index=0; index<[rssGroups count]; index++) {

            NSString * urlString = [[[rssGroups objectAtIndex:index] source] link];

            NSURL *url = [NSURL URLWithString:urlString];

            ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request setDelegate:self];

            //set this request's tag to group index of this source(link). See requestFinished for use of this :)
            [request setTag:index];

            [self.queue addOperation:request];
        }

}


- (void)requestFinished:(ASIHTTPRequest *)request {

    NSLog(@"%@",@"RSS Data got from internet successfully :))");


    int groupIndex = [request tag];

    CompleteRSSDataModel * group = [rssGroups objectAtIndex:groupIndex];

    group.parser = [[KissXMLParser alloc]initWithData:[request responseData]];

    if (group.parser == nil) {

        NSLog(@"%@",@"Failed - Error in parsing data :((");
    }

    else {
        NSLog(@"%@",@"Data Parsed successfully :))");

        group.rssArticles = [group.parser itemsInRss];

        //So i want to check here that queue is empty, reload data, but as my information, i don't know any method like hasCompletedAllRequested 

        //if(self.queue hasCompletedAllRequests) {

        //     [self.tableview reloadData];
        //}


    }
}

- (void)requestFailed:(ASIHTTPRequest *)request {

    NSLog(@"%@",@"Error in Getting RSS Data from internet:((");

}

【问题讨论】:

  • 您可能想在这里分享您已经尝试过的东西——即研究、遇到的问题等。对于任何愿意提供帮助的人来说,一堵代码实际上并没有任何帮助.
  • 也许你是对的。我需要编辑问题。谢谢建议

标签: iphone objective-c ios5 asihttprequest nsoperationqueue


【解决方案1】:

如果所有操作都已完成,那么operations 数组计数将为零。

要检查这一点,您可以使用键值观察编码来观察 operationsNSOperationQueue

为键 opertions 设置观察者将如下所示:

[self.queue addObserver:self forKeyPath:@"operations" options:0 context:NULL];

然后在您的 observeValueForKeyPath 中执行此操作,如下所示:

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
                         change:(NSDictionary *)change context:(void *)context
{
    if (object == self.queue && [keyPath isEqualToString:@"operations"]) {
        if ([self.queue.operations count] == 0) {
            // Do something here when all operations has completed
            NSLog(@"queue has completed");
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object 
                               change:change context:context];
    }
}

iOS 4.0 之后你可以像self.queue.operationCount == 0 这样使用属性operationCount 而不是像[self.queue.operations count] == 0 这样检查

【讨论】:

    【解决方案2】:

    我知道这个问题已经得到解答,但对于未来的读者,如果您使用 AFNetworking,更具体地说,AFHTTPRequestOperation,您可以执行以下操作:

    NSString *urlPath = [NSString stringWithFormat:@"%@%@", baseUrl, file];
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlPath]];
    
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    
    [operation setCompletionBlockWithSuccess:
     ^(AFHTTPRequestOperation *operation, id responseObject) {
       if ([[queue operations] count] ==0) {
           NSNotification * success = [NSNotification notificationWithName:@"TotalDone" object:[NSNumber numberWithBool: YES]];
          [[NSNotificationCenter defaultCenter] postNotification:success];
          queueSize = 0;
       } else {
    
           //get total queue size by the first success and add 1 back
           if (queueSize ==0) {
               queueSize = [[queue operations] count] +1.0;
           }
           float progress = (float)(queueSize-[[queue operations] count])/queueSize;
           NSNumber * totProgress = [NSNumber numberWithFloat:progress];
           NSNotification * totalProgressNotification = [NSNotification notificationWithName:@"TotalProgress"
                                                                                               object:totProgress];
           [[NSNotificationCenter defaultCenter] postNotification:totalProgressNotification];
       }
    
    
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) 
            NSLog(@"Error: %@", error);
            }];
    

    这适用于将下载添加到 NSOperationQueue 的下载器,然后通知两个进度条:1 个用于文件进度,1 个用于总进度。

    希望对你有帮助

    【讨论】:

      【解决方案3】:

      我突然想到了几个选项:

      1. 改用ASINetworkQueue,并设置queueDidFinishSelector,这样它会在完成时告诉你。这也让您有机会不仅更新单个行的 UIProgressView 视图,还可以更新整个下载过程的另一个视图。

      2. 您能否在您的NSOperationQueue 中添加一些内容,以简单地调用一个方法来更新您的 UI(当然是在主队列中)?通过将它添加到队列中,它不会到达它,直到它清除队列。或者在另一个队列中,调用 waitUntilFinished,此时您可以更新您的 UI。

      3. 查看您的 cmets,您似乎正在更新 requestFinished 中的 UI,但您不满意,因为您认为等待所有更新发生可能会更好。就个人而言,我更喜欢逐个请求更新 UI,这样如果速度很慢,你会得到临时反馈,而不是等待一切。这必须优雅地完成,但我喜欢在进行过程中更新 UI。诚然,有些流程不适合这样做。

      关于最后一点,我认为诀窍是进行这些更新,以免分散注意力。具体来说,如果您的 UI 是 UITableView,您可能想要执行 tableView.reloadData,这将重新加载整个表格。相反,您可能想检查单元格是否仍在加载(通过cellForRowAtIndexPathUITableView 方法,不要与UITableViewController 方法tableView:cellForRowAtIndexPath 混淆)如果是,更新那一行,例如:

      NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:section];
      UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
      if (cell)
      {
          // you can either update the controls in the cell directly, or alternatively, just
          // call reloadRowsAtIndexPaths to have the tableView use your data source:
      
          [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                                withRowAnimation:UITableViewRowAnimationFade];
      }
      

      【讨论】:

      • 你是对的。目前我正在更新 requestFinished 中的 ui,但我觉得这不是正确的方法。我认为 ASINetworkQueue 可能是一个不错的选择。我要试试。但我想问一下,它会像 NSOperationQueue 那样在后台进行所有下载吗?
      • 是的,它在我的代码中。此外,它还提供了一些其他好处(例如,如果您使用 UIProgressView,您可以为整个排队作业提供一个)。
      • 目前我正在更新 requestFinished 中的 ui,如你所说。但问题是当我有多个请求时,我需要在所有请求完成后更新 ui。然后我使用 [self.queue.operation count] 消息解决了它。当它变为零时,我可以安全地更新 ui。现在我可以使用此方法显示下载进度。无论如何谢谢:)
      • @iMemon 我个人认为在每次requestFinished 之后更新 UI 是件好事。不过,诀窍是不要更新整个 UI,而只是更新适当的行。我已经相应地更新了我的答案。显然,您可以等到最后(在这种情况下,我不会推荐self.queue.operation.count,而是我会使用setQueueDidFinishSelector 来指定队列完成时要调用的方法),但我认为对于每个requestFinished,在数据进入时无缝更新 UI 是一种更好的用户体验。
      猜你喜欢
      • 1970-01-01
      • 2011-01-30
      • 1970-01-01
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-13
      • 2010-10-14
      相关资源
      最近更新 更多