Ale*_*Ale 5 background fetch ios7 nsurlsession
我想使用NSUrlSession下载文件列表.
我有一个用于计算成功下载量的变量@property (nonatomic) int downloadsSuccessfulCounter;.在下载文件时我禁用了Download Button.当计数器等于下载列表大小时,我再次启用该按钮并将计数器设置为0.我在方法中执行此操作:
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location {
...
[[NSOperationQueue mainQueue] addOperationWithBlock:^ {
downloadsSuccessfulCounter++;
if(downloadsSuccessfulCounter == self.downloadList.count) {
NSLog(@"All downloads finished");
[self.syncButton setEnabled:YES];
downloadsSuccessfulCounter = 0;
}
}];
Run Code Online (Sandbox Code Playgroud)
}
一切都运行正常,但当我再次打开ViewController时,我得到了消息A background URLSession with identifier com.myApp already exists!.计数器未设置为0,UI元素(UIButtons,UILabels)没有响应.
我想问题是因为NSURLSession仍然是开放的,但我不确定它是如何工作的.
我已经尝试了所有的教程,但其中99%仅用于下载1个文件,不超过1个...任何想法?
这是我的代码:
...
@property (nonatomic, strong) NSURLSession *session;
...
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
self.downloadList = [[NSMutableArray alloc] init];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.myApp"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
}
Run Code Online (Sandbox Code Playgroud)
当我按下Download Button我调用此方法时(我有一个Downloadable包含a 的对象NSURLSessionDownloadTask):
-(void)startDownload {
for (int i=0; i<[self.downloadList count]; i++) {
Downloadable *d = [self.downloadList objectAtIndex:i];
if (!d.isDownloading) {
if (d.taskIdentifier == -1) {
d.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:d.downloadSource]];
}else {
d.downloadTask = [self.session downloadTaskWithResumeData:fdi.taskResumeData];
}
d.taskIdentifier = d.downloadTask.taskIdentifier;
[d.downloadTask resume];
d.isDownloading = YES;
}
}
}
Run Code Online (Sandbox Code Playgroud)
当应用程序处于后台时:
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([downloadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
appDelegate.backgroundTransferCompletionHandler = nil;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
completionHandler();
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = @"All files downloaded";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}];
}
}
}];
}
Run Code Online (Sandbox Code Playgroud)
因此,正如我在评论中提到的,问题是每个文件都需要一个唯一的 NSURLSession,并且每个 NSURLSession 需要一个具有唯一标识符的 NSURLSessionConfiguration。
我认为你很接近 - 并且在某些方面可能比我更合适......你只需要创建一个结构来将唯一的 ID 传递到唯一的配置中,以填充唯一的会话(比如说快 10 倍)。
这就是我所做的:
/* * 检索要下载的文件列表 * 还使用该列表的大小来实例化项目 * 在我的例子中,我加载一个字符返回的文本文件,其中包含我要下载的文件的名称 */
- (void) getMediaList {
NSString *list = @"http://myserver/media_list.txt";
NSURLSession *session = [NSURLSession sharedSession]; // <-- BASIC session
[[session dataTaskWithURL:[NSURL URLWithString:list]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSString *stringFromData = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
// Populate Arrays
REMOTE_MEDIA_FILE_PATHS = [stringFromData componentsSeparatedByString:@"\n"];
[self instantiateURLSessions:[REMOTE_MEDIA_FILE_PATHS count]];
// Start First File
[self getFile:[REMOTE_MEDIA_FILE_PATHS objectAtIndex:downloadCounter]:downloadCounter]; // this variable is 0 at the start
}]
resume];
}
Run Code Online (Sandbox Code Playgroud)
/* * 这会将配置和会话数组设置为适当的大小 * 它还为每个数组提供唯一的 ID */
- (void) instantiateURLSessions : (int) size {
NSMutableArray *configurations = [NSMutableArray array];
NSMutableArray *sessions = [NSMutableArray array];
for (int i = 0; i < size; i++) {
NSString *index = [NSString stringWithFormat:@"%i", i];
NSString *UniqueIdentifier = @"MyAppBackgroundSessionIdentifier_";
UniqueIdentifier = [UniqueIdentifier stringByAppendingString:index];
[configurations addObject: [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:UniqueIdentifier]];
[sessions addObject:[NSURLSession sessionWithConfiguration: [configurations objectAtIndex:i] delegate: self delegateQueue: [NSOperationQueue mainQueue]]];
}
NSURL_BACKGROUND_CONFIGURATIONS = [NSArray arrayWithArray:configurations];
NSURL_BACKGROUND_SESSIONS = [NSArray arrayWithArray:sessions];
}
Run Code Online (Sandbox Code Playgroud)
/* * 这根据数组的索引为每个文件设置下载任务 * 它还连接到实际文件的路径 */
- (void) getFile : (NSString*) file :(int) index {
NSString *fullPathToFile = REMOTE_MEDIA_PATH; // Path To Server With Files
fullPathToFile = [fullPathToFile stringByAppendingString:file];
NSURL *url = [NSURL URLWithString:fullPathToFile];
NSURLSessionDownloadTask *downloadTask = [[NSURL_BACKGROUND_SESSIONS objectAtIndex:index ] downloadTaskWithURL: url];
[downloadTask resume];
}
Run Code Online (Sandbox Code Playgroud)
/* * 最后,在我的委托方法中,下载完成后(将文件从临时数据中移出后),我检查是否已完成,如果没有,则使用更新后的索引计数器再次调用 getFiles 方法 * /
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
// Get the documents directory URL
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *dataPath = [documentsDirectory stringByAppendingPathComponent:LOCAL_MEDIA_PATH];
NSURL *customDirectory = [NSURL fileURLWithPath:dataPath];
// Get the file name and create a destination URL
NSString *sendingFileName = [downloadTask.originalRequest.URL lastPathComponent];
NSURL *destinationUrl = [customDirectory URLByAppendingPathComponent:sendingFileName];
// Move the file
NSError *error = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
if ([fileManager moveItemAtURL:location toURL:destinationUrl error: &error]) {
// List
[self listCustomDirectory];
if(downloadCounter < [REMOTE_MEDIA_FILE_PATHS count] -1) {
// Increment Counter
downloadCounter++;
// Start Next File
[self getFile:[REMOTE_MEDIA_FILE_PATHS objectAtIndex:downloadCounter]:downloadCounter];
}
else {
// FINISH YOUR OPERATION / NOTIFY USER / ETC
}
}
else {
NSLog(@"Damn. Error %@", error);
// Do Something Intelligent Here
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6174 次 |
| 最近记录: |