2013-01-15 70 views
2

在我目前的设计中,我有一个表示文件夹结构的tableview。当用户点击单元格时,将创建一个AFHTTPRequestOperation以下载文件。当单元格当前显示当前下载状态时,下载该文件:无/下载/下载。AFNetworking完成块

下载状态设置在对应于每个单元的NSManagedObject上。在我的下载完成块中,我将下载状态设置为“已下载”标志。问题在于如果用户从当前的tableview数据导航到另一个,竞争块将设置错误的NSManagedObject - 它根据NSIndex进行查找。

简而言之,我想知道如何将对象与我的AFHTTPRequestOperation一起传递,以便在完成时可以对其执行操作。它可以像int或string一样简单,我可以根据此值执行NSPredicate请求。

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 
     [self.operations addObject:operation]; 
     [self.inProgressDownloads addObject:indexPath]; 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
     NSString *extension = [[self.selectedFile.name componentsSeparatedByString:@"."] lastObject]; 
     NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat: @"%@.%@", self.selectedFile.item_id, extension]]; 
     operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO]; 
     self.selectedFile.status = DOWNLOADING; 
     [self.tableView beginUpdates]; 
     [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone]; 
     [self.tableView endUpdates]; 

     [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
      NSLog(@"File downloaded to: %@", path); 
      self.selectedFile.status = DOWNLOADED; 
      self.selectedFile.is_stored = @YES; 
      [self.tableView beginUpdates]; 
      [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone]; 
      [self.tableView endUpdates]; 
     } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 
      NSLog(@"Error: %@", error); 
      self.selectedFile.status = DOWNLOAD_ERROR; 
     }]; 

     [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) { 
      dispatch_async(dispatch_get_main_queue(), ^{ 
       float percent = (float)totalBytesRead/(float)totalBytesExpectedToRead; 
       NSLog(@"totalBytesExpectedToRead %d", (int)(percent * 100)); 
      }); 
     }]; 

     [operation start]; 

回答

3

概括地说,我想知道我可以一起传递一个对象与我AFHTTPRequestOperation以便在完成上就可以进行操作。它可以像int或string一样简单,我可以根据此值执行NSPredicate请求。

这是关闭/块的权力发挥作用的地方。你不需要将任何特殊的东西传递给一个块。您可以引用任何在块中可以词汇显示的对象,并且在块运行时它将可用。

Apple docs(具体地,第2点):

块表示的代码通常较小,自包含块。因此,它们作为封装可能同时执行的工作单元或集合中的项目,或作为其他操作完成时的回调的手段特别有用。

块是传统的回调函数一个有用的替代主要有两个原因:

  1. 它们允许你在那个在方法执行方面稍后执行调用的点写代码。
    块因此通常是框架方法的参数。

  2. 它们允许访问局部变量。
    而不是使用需要数据结构的回调来体现执行操作所需的所有上下文信息,而只需直接访问本地变量。

如果我理解正确的话你正在尝试做的,这应该工作:

TYPE_HERE* localSelectedFile = self.selectedFile; 

    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) { 
     NSLog(@"File downloaded to: %@", path); 
     localSelectedFile.status = DOWNLOADED; 
     localSelectedFile.is_stored = @YES; 
     [self.tableView beginUpdates]; 
     [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationNone]; 
     [self.tableView endUpdates]; 
     ... 

我在哪里存储self.selectedFile值到一个局部变量在执行operation时刻;那么我将该局部变量用于块体。这是合法的(这就是我所指的闭包的力量:它们保留有关它们执行上下文的信息),并会给你提供你正在处理的对象的引用。

您可能会发现this有趣的整体看法。

+0

请检查我编辑的答案,我已经为您的特定情况添加了解决方案。 – sergio

+0

棒极了,塞尔吉奥。这是我的问题,错误的范围!谢谢! – Shocks

+0

很高兴有帮助。 – sergio