2

在我目前的设计中,我有一个代表文件夹结构的表格视图。当用户点击一个单元格时,AFHTTPRequestOperation会创建一个来下载文件。当单元格当前显示当前下载状态时下载文件:无/已下载/正在下载。

下载状态设置在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];
4

1 回答 1

3

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

这就是闭包/块的力量发挥作用的地方。您不需要将任何特殊的东西传递到块中。您可以引用块中词法可见的任何对象,并且在运行块时可用。

来自Apple 文档(特别是第 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;然后我将该局部变量用于块体。这是合法的(这就是我所指的闭包的力量:它们自己保存有关其执行上下文的信息)并将为您提供对您正在处理的对象的引用。

对于整体视图,您可能会觉得这很有趣。

于 2013-01-15T15:16:59.823 回答