【问题标题】:AFNetworking. Check download progress for all operation queueAF网络。检查所有操作队列的下载进度
【发布时间】:2013-03-01 15:58:45
【问题描述】:

我有一个使用 AFNetworking 制作的 iOS 应用程序。 我有一个单例自定义 httpclient 子类,我用它来使用我的 api 并从服务器下载二进制文件。

我需要下载大约 100 个文件。遍历我的 url 数组并为每个 url 创建一个 AFHTTPRequestionOperation 是否安全?我的代码是这样的:

NSMutableURLRequest* rq = [[MIHTTPClient sharedInstance] requestWithMethod:@"GET" path:@"...." parameters:nil];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:rq] ;
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];

[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    //completion

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    //manage error
}];


[[MIHTTPClient sharedInstance] enqueueHTTPRequestOperation:operation];

我如何才能收到来自此队列的反馈?我没有看到任何“HTTPClientDelegate”协议或类似的东西。

【问题讨论】:

    标签: ios afnetworking


    【解决方案1】:

    关于进度,请参见setDownloadProgressBlockAFURLConnectionOperation 的一部分,AFHTTPRequestOperation 是其中的子类),例如:

    [operation setDownloadProgressBlock:^(NSInteger bytesWritten, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) {
        NSLog(@"Sent %d of %d bytes, %@", totalBytesWritten, totalBytesExpectedToWrite, path);
    }];
    

    并且,在您的代码示例中,您正在调用setCompletionBlockWithSuccess:failure:,以便提供有关各个操作完成的状态。就个人而言,在我的小测试中,我只维护了一组我请求的下载,并让这三个块(进度、成功和失败)更新我的下载状态代码,如下所示:

    for (NSInteger i = 0; i < 20; i++)
    {
        NSURLRequest *request = ... // set the request accordingly
    
        // create a download object to keep track of the status of my download
    
        DownloadObject *object = [[DownloadObject alloc] init];
        download.title = [NSString stringWithFormat:@"Download %d", i];
        download.status = kDownloadObjectStatusNotStarted;
        [self.downloadObjects addObject:download];
    
        AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    
        [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            download.status = kDownloadObjectStatusDoneSucceeded;
    
            // update my UI, for example, I have table view with one row per download
            //
            // [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]
            //                       withRowAnimation:UITableViewRowAnimationNone];
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            download.status = kDownloadObjectStatusDoneFailed;
    
            // update UI
            //
            // [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]
            //                       withRowAnimation:UITableViewRowAnimationNone];
        }];
    
        [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
            download.totalBytesRead = totalBytesRead;
            download.status = kDownloadObjectStatusInProgress;
    
            // update UI
            //
            // [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:i inSection:0]]
            //                       withRowAnimation:UITableViewRowAnimationNone];
        }];
    
        [queue addOperation:operation];
    }
    

    您可以通过这种方式跟踪各个下载。您也可以只跟踪待处理的操作(或查询HTTPClient 对象的operationQueue 属性,然后查看其operationCount 属性)。


    在下载100个文件方面,有两个考虑:

    • 我原以为您想在您的 HTTPClient 子类的 operationQueue 上调用 setMaxConcurrentOperationCount,将其设置为某个合理的数字(4 或 5),就像浏览 AFNetworking 代码一样,它似乎没有这样做。我发现如果你超出这个范围,回报就会递减,并且如果所有文件都来自单个服务器,那么在给定客户端和给定服务器之间可以执行多少并发操作是有限制的。

    • 我读过传闻称 Apple 将拒绝通过蜂窝网络发出特殊请求的应用程序。见https://stackoverflow.com/a/14922807/1271826

    【讨论】:

    • setDowloadProgressBlock 对于单个连接很有用,我使用它。我正在为整个队列寻找相同的功能。感谢 setMaxConcurrentOperationCount...AFN 代码将此值设置为 NSOperationQueueDefaultMaxConcurrentOperationCount (-1)
    • @IgnazioC 是的,我看到了他们设置maxConcurrentOperationCount 的位置,这正是我指出如果你打算做 100 的话,将它重置为 4 或 5 对你来说很重要的原因下载。如果您不这样做,它将同时启动所有 100 个操作,而后者最终将超时。设置maxConcurrentOperationCount 将解决该问题。在进行大量下载时始终很重要。
    • “整个队列”的重新进度,在操作的下载进度块和操作的两个完成块之间,您拥有所需的一切。您可以跟踪未决下载的计数,或者在我更新的答案中,在单独的数组中跟踪单个下载的状态。虽然我可以理解您可能想要一个块来表示整个队列的状态,但考虑到其他三个块,这是多余的。
    • 这是一个非常有趣的解决方案。但是,因为当您遍历要下载的项目列表并创建 AFHTTPRequestOperation 对象时,您也在重新创建 DownloadObject 对象。当downloadProgressBlock 方法触发时,它如何知道要引用哪个DownloadObject 块? Objective-C 是否知道要保留在for 循环的迭代上下文中创建的特定DownloadObject,以便在downloadProgressBlock 被触发时?
    • @Jason 是的,您的 downloadProgressBlock 已被调用,您可以在该块中引用索引 i,或者您可以引用 DownloadObject 本身(它将引用正确的一个)。
    猜你喜欢
    • 2015-11-06
    • 2013-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-29
    相关资源
    最近更新 更多