Ios 使用NSURLSession下载多个文件,并将其进度保持在后台状态

Ios 使用NSURLSession下载多个文件,并将其进度保持在后台状态,ios,ios7,nsurlconnection,nsurlsession,Ios,Ios7,Nsurlconnection,Nsurlsession,我使用NSURLSession下载了一个文件,它工作正常,现在我必须在后台下载三个文件,还必须在UIProgress中管理它们的进度。我的单次下载代码如下 - (IBAction)startBackground:(id)sender { // Image CreativeCommons courtesy of flickr.com/charliematters NSString *url = @"http://farm3.staticflickr.com/2831/982389

我使用NSURLSession下载了一个文件,它工作正常,现在我必须在后台下载三个文件,还必须在UIProgress中管理它们的进度。我的单次下载代码如下

- (IBAction)startBackground:(id)sender 
{
    // Image CreativeCommons courtesy of flickr.com/charliematters
    NSString *url = @"http://farm3.staticflickr.com/2831/9823890176_82b4165653_b_d.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    self.backgroundTask = [self.backgroundSession downloadTaskWithRequest:request];
    [self setDownloadButtonsAsEnabled:NO];
    self.imageView.hidden = YES;
    // Start the download
    [self.backgroundTask resume];
}

- (NSURLSession *)backgroundSession
{
    static NSURLSession *backgroundSession = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionConfiguration *config = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.shinobicontrols.BackgroundDownload.BackgroundSession"];
        backgroundSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
    });
    return backgroundSession;
}

#pragma mark - NSURLSessionDownloadDelegate methods
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    double currentProgress = totalBytesWritten / (double)totalBytesExpectedToWrite;
    dispatch_async(dispatch_get_main_queue(), ^{
        self.progressIndicator.hidden = NO;
        self.progressIndicator.progress = currentProgress;
    });
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
    // Leave this for now
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    // We've successfully finished the download. Let's save the file
    NSFileManager *fileManager = [NSFileManager defaultManager];

    NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
    NSURL *documentsDirectory = URLs[0];

    NSURL *destinationPath = [documentsDirectory URLByAppendingPathComponent:[location lastPathComponent]];
    NSError *error;

    // Make sure we overwrite anything that's already there
    [fileManager removeItemAtURL:destinationPath error:NULL];
    BOOL success = [fileManager copyItemAtURL:location toURL:destinationPath error:&error];

    if (success)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            UIImage *image = [UIImage imageWithContentsOfFile:[destinationPath path]];
            self.imageView.image = image;
            self.imageView.contentMode = UIViewContentModeScaleAspectFill;
            self.imageView.hidden = NO;
        });
    }
    else
    {
        NSLog(@"Couldn't copy the downloaded file");
    }

    if(downloadTask == cancellableTask) {
        cancellableTask = nil;
    } else if (downloadTask == self.resumableTask) {
        self.resumableTask = nil;
        partialDownload = nil;
    } else if (session == self.backgroundSession) {
        self.backgroundTask = nil;
        // Get hold of the app delegate
        SCAppDelegate *appDelegate = (SCAppDelegate *)[[UIApplication sharedApplication] delegate];
        if(appDelegate.backgroundURLSessionCompletionHandler) {
            // Need to copy the completion handler
            void (^handler)() = appDelegate.backgroundURLSessionCompletionHandler;
            appDelegate.backgroundURLSessionCompletionHandler = nil;
            handler();
        }
    }

 }

 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
 {
     dispatch_async(dispatch_get_main_queue(), ^{
        self.progressIndicator.hidden = YES;
        [self setDownloadButtonsAsEnabled:YES];
     });
 }

您可以让多个NSURLSessionDownloadTask使用同一NSSession,并且每个NSURLSessionDownloadTask都在同一主队列上逐个执行

成功下载后,他们会调用:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
如果下载100MB的MP4和10KB的pic,它们将以不同的顺序返回到该方法中

因此,要跟踪此会话中返回的会话和下载任务

在调用web服务之前,需要设置字符串标识符

要区分/跟踪您设置的NSURLSessions

session.configuration.identifier
要区分NSURLSessionDownloadTask,请使用

downloadTask_.taskDescription

downloadTask_.taskDescription =  [NSString stringWithFormat:@"%@",urlSessionConfigurationBACKGROUND_.identifier];
例如,在我的项目中,我下载了许多用户喜爱的视频和它们的缩略图

每个项目都有一个id,例如1234567 所以我需要为每个最喜欢的人打两个电话

所以我创建了两个标识符

"1234567_VIDEO"
"1234567_IMAGE"
然后调用了两个ws调用,并在session.configuration.identifier中传入标识符

http://my.site/getvideo/1234567
"1234567_VIDEO"

http://my.site1/getimage/1234567
"1234567_IMAGE"
iOS7将在后台下载项目,应用程序可以返回睡眠状态 完成后会调用

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
然后我得到

session.configuration.identifier
"1234567_IMAGE"
将其拆分并检查值

1234567_IMAGE
"1234567"
"_IMAGE"   > item at location is a MP4 so save as /Documents/1234567.mp4
"_VIDEO"   > item at location is a jpg so save as /Documents/1234567.jpg
如果要调用3个URL,则每个NSSession可以有一个NSURLSessionDownloadTask

file 1 - NSSession1 > NSURLSessionDownloadTask1
file 2 - NSSession2 > NSURLSessionDownloadTask2
file 3 - NSSession3 > NSURLSessionDownloadTask3
当应用程序位于前台时,这似乎可以正常工作。 但是我在使用后台传输和后台提取时遇到了问题。 第一个NSSession>NSURLSessionDownloadTask1将返回,然后不会调用任何其他任务

因此,在一个NSSession1中有多个NSURLSessionDownloadTask更安全

file 1 - NSSession1 > NSURLSessionDownloadTask1
file 2 -            > NSURLSessionDownloadTask2
file 3 -            > NSURLSessionDownloadTask3
做这件事时要小心 调用NSSession FinishTasks和Invalidate not invalidateAndCancel

  //[session invalidateAndCancel];
   [session finishTasksAndInvalidate];

invalidateAndCancel将停止会话,而不会完成其他下载任务

。。。你的问题是什么?如果我必须下载三个文件,这段代码只适用于一次下载。我将如何管理..我没有得到..请帮助获取多个文件。如果你可以为一个文件执行此操作,将其扩展到进一步下载有什么困难?就像在代码中一样,它正在创建后台会话NSURLSessionConfiguration*config=[NSURLSessionConfiguration backgroundSessionConfiguration:@“com.shinobicontrols.BackgroundDownload.BackgroundSession”];如何处理多个文件我每次都需要一个不同的包标识符,而且进度条也有问题它总是在更新进度条..看到很多无用的评论,比如“What is your question”(你的问题是什么)真让人难过。。。问题是非常清楚的,“如果你可以为一个文件做这件事,那么扩展到进一步下载有什么困难?”。如果你知道如何解决这个问题,为什么不写下一个答案呢?NSURLSession如何让你知道当所有的文件都下载完毕,而应用程序不需要背景?当所有下载任务完成时,委托方法确实会被调用,但只有在我将我的应用程序设置为后台时才会被调用。当应用程序仍在运行时,我需要它。@NYCTechEngineer将所有任务添加到数组中,然后使用let downloadsCompleted=(downloadstasks.indexOf({$0.state==NSURLSessionTaskState.running})=nil)?真:假,表示他们已经完成。