我已经使用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];
});
}
答案 0 :(得分:5)
你可以让多个NSURLSessionDownloadTask使用相同的NSSession,并且每个NSSession在同一个mainQueue上一个接一个地执行。
成功下载后,他们致电:
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
如果您下载100 mB的MP4和10KB的图片,那么他们将以不同的顺序返回此方法。
因此,要跟踪此
中返回的会话和downloadTask您需要在调用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将在后台下载项目,app可以回去睡觉
完成后调用
- (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个网址可以调用,则每个NSSession可以有一个NSURLSessionDownloadTask
file 1 - NSSession1 > NSURLSessionDownloadTask1
file 2 - NSSession2 > NSURLSessionDownloadTask2
file 3 - NSSession3 > NSURLSessionDownloadTask3
当应用程序位于前台时,这似乎工作正常。 但是当使用BACKGROUND TRANSFER和BACKGROUND FETCH时我遇到了问题。 第一个NSSession> NSURLSessionDownloadTask1将返回,然后不会调用其他任何一个。
在一个NSSession1中有多个NSURLSessionDownloadTask更安全
file 1 - NSSession1 > NSURLSessionDownloadTask1
file 2 - > NSURLSessionDownloadTask2
file 3 - > NSURLSessionDownloadTask3
这样做时要小心 调用NSSession finishTasksAndInvalidate not invalidateAndCancel
//[session invalidateAndCancel];
[session finishTasksAndInvalidate];
invalidateAndCancel将停止会话而不完成其他下载任务