NSURLSessionDownloadTask, как вы хорошо знаете, не очень хорошо работает с NSOperationQueues, в отличие от их аналога NSURLConnection (где он может быть инкапсулирован внутри NSOperation).
Одним из вариантов было бы добавить все ваши URL-адреса в массив, а затем внутри обработчика завершения задачи просто поставить в очередь следующий элемент.
Таким образом, вы можете создавать свои задачи в цикле, вызывать 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 на nil, чтобы предотвратить любые циклы сохранения.
person
Daniel Galasko
schedule
10.10.2014