2014-10-10 32 views
1

在我的应用程序中,我从Web服务中获取JSON。这个JSON包含我想下载的几个文件的URL。使用NSURLSessionDownloadTask一个接一个下载文件

我想用NSURLSessionDownloadTask一个一个下载每个文件(等待第一个下载完成,直到第二个下载完成,等等等等)。我还想跟踪写入的总字节数,以便我可以更新UI。

非常感谢!

+0

我认为我的解决方案不是你要找的?请评论和说明它是不正确的? – 2014-10-12 06:57:04

回答

2

NSURLSessionDownloadTask就像你知道NSOperationQueues不像NSURLConnection(它可以封装在一个NSOperation里面)一样不会很好地播放。

一个选择是将所有的url添加到一个数组,然后在任务的completionHandler中,简单地排队下一个项目。

所以,你可能在一个循环中创建任务,调用每个任务完成处理内部progressBlock,存储任务的数组,队列中的每个任务的完成处理程序中的下一个任务:

- (void)addRequestsWithURLs:(NSArray *)urls 
       progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations, NSURLSessionDownloadTask *task,NSURL *location, NSURLResponse *response, NSError *error))progressBlock { 
    __block NSUInteger numberOfFinishedOperations = 0; 
    NSUInteger totalNumberOfOperations = [urls count]; 
    for (NSString *url in urls) { 
     NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]]; 
     __block NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:request 
                   completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { 
                    //downloadFileSomewhere 

                    ++numberOfFinishedOperations; 
                     if (progressBlock) { 
                      progressBlock(numberOfFinishedOperations, totalNumberOfOperations,task,destination != nil ? [NSURL fileURLWithPath:destination] : nil,response,error); 

                     } 
                    //queueNext 
                    [self processCompletedTask:task]; 
                   }]; 
     //stores an array of NSURLSessionTasks 
     [self.tasksWaitingToBeQueued addObject:task]; 
    } 

} 

- (void)processCompletedTask:(NSURLSessionTask *)completedTask { 
    //clean up and queue next one 
    [self.tasksWaitingToBeQueued removeObject:completedTask];   
    nextTask = [self.tasksWaitingToBeQueued firstObject]; 
    if (nextTask) { 
     [nextTask resume]; 
    } 
} 

注意

在这个例子中,我将进度表示为完成的任务数,而不是字节数,这是推荐的方法(它也更简单)。要使用字节指示进度,您需要事先知道要下载的总字节数(因为您想显示进度条),并且还要实现NSURLSession委托并监视每个任务的进度,捕获下载的字节并更新您的块。如果你的服务器没有告诉你总的字节数,那么你可能需要为每个资源做一个HEAD请求并聚合这些大小。就个人而言,这种解决方案是复杂的,可以简单地通过将进度指示为下载的文件数来解决。

要做到这一点可能是这个样子:

- (void)URLSession:(NSURLSession *)session 
     downloadTask:(NSURLSessionDownloadTask *)downloadTask 
     didWriteData:(int64_t)bytesWritten 
totalBytesWritten:(int64_t)totalBytesWritten 
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { 
    self.totalBytesWritten += totalBytesWritten; 
    NSUInteger totalProgressSoFar = self.totalBytesWritten; 
    NSUInteger totalExpectedBytes = self.totalExpectedBytes; 
    //you would need to capture some progress block locally - beware of retain cycles 
    self.progressBlock(totalProgressSoFar/totalExpectedBytes) 
} 

当你完成你应该progressBlock为零设置为prevent any retain cycles

+0

非常感谢您的回答。我用你提出的建议,它似乎工作。再次感谢 ! – Vinestro 2014-10-13 11:57:43

+0

@Vinestro真棒!听到那个消息很开心 :) – 2014-10-14 12:47:55