0

目前我正在实施文件下载应用程序。 在我的应用程序服务器中有大约2500个资源文件,我需要将这些文件从服务器下载到我的文档目录。遇到多个文件下载问题

我的代码:

@implementation DownloadManager 
{ 
    NSURLSession *session; 
    BOOL downloading; 
} 

#pragma mark - NSURLSessionDownloadDelegate 

// Handle download completion from the task 
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location 
{ 
    NSInteger index = [self assetDownloadIndexForDownloadTask:downloadTask]; 
    if (index < 0) 
    { 
     return; 
    } 
    DownloadHelper *movieDownload = _assetsToDownload[index]; 

    // Copy temporary file 
    NSError * error; 
    [[NSFileManager defaultManager] copyItemAtURL:location toURL:[NSURL fileURLWithPath:[movieDownload localPath]] error:&error]; 
    downloading = NO; 
} 

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes 
{ 
    // Required delegate method 
} 

// Handle task completion 
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error 
{ 
    if (error) 
     NSLog(@"Task %@ failed: %@", task, error); 
    NSLog(@"Task %@ Success: %@", task, error); 
    if ([_assetsToDownload count]) 
    { 
     [_assetsToDownload removeObjectAtIndex:0]; 
    } 

    downloading = NO; 
    if ([_assetsToDownload count]) 
    { 
     [self downloadFiles]; 
    } 
    else 
    { 
     [self downloadAssets]; 
    } 
} 

// Handle progress update from the task 
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite 
{ 
    NSInteger index = [self assetDownloadIndexForDownloadTask:downloadTask]; 
    if (index < 0) return; 
    // DownloadHelper *movieDownload = _assetsToDownload[index]; 
    double progress = (double) (totalBytesWritten/1024)/(double) (totalBytesExpectedToWrite/1024); 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // Showing progress 
    }); 

} 

#pragma mark - Movie Download Handling & UI 

// Helper method to get the index of a Asset from the array based on downloadTask. 
- (NSInteger)assetDownloadIndexForDownloadTask:(NSURLSessionDownloadTask *)downloadTask 
{ 
    NSInteger foundIndex = -1; 
    NSInteger index = 0; 
    for (DownloadHelper *asset in _assetsToDownload) 
    { 
     if (asset.downloadTask == downloadTask) 
     { 
      foundIndex = index; 
      break; 
     } 
     index++; 
    } 
    return foundIndex; 
} 

- (void)addAssetDownload 
{ 
    DownloadInfo *info = nil; 
    NSString *assetFolder = nil; 
    for (int index = 0; index<[_assets count]; index++) 
    { 
     info         = [_assets objectAtIndex:index]; 
     NSURL *url        = [NSURL URLWithString:info.assetURL]; 
     NSURLRequest *request     = [NSURLRequest requestWithURL:url]; 
     NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; 

     DownloadHelper *assetDownload  = [[DownloadHelper alloc] initWithURL:url downloadTask:downloadTask]; 
     assetDownload.assetName     = info.assetName; 

     if (info.categoryId == 1) 
     { 
      assetFolder = [self getImagePath:info.assetName]; 
     } 
     else if (info.categoryId == 2) 
     { 
      assetFolder = [self getVideoPath:info.assetName]; 
     } 
     else if (info.categoryId == 3) 
     { 
      //assetFolder = [self getDBPath:info.assetName]; 
     } 
     else 
     { 
      assetFolder = [self filePath:info.assetName]; 
     } 
     assetDownload.assetFolder = assetFolder; 
     [_assetsToDownload addObject:assetDownload]; 
    } 
} 

// Initialize the download, session and tasks 
- (void)initialize 
{ 
    for (DTEDownloadHelper *movieDownload in _assetsToDownload) 
    { 
     // Cancel each task 
     NSURLSessionDownloadTask *downloadTask = movieDownload.downloadTask; 
     [downloadTask cancel]; 
    } 

    // Cancel all tasks and invalidate the session (also releasing the delegate) 
    [session invalidateAndCancel]; 
    session = nil; 

    _assetsToDownload = [[NSMutableArray alloc] init]; 

    // Create a session configuration passing in the session ID 
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"DTEDownloadBackground"]; 
    sessionConfiguration.discretionary = YES; 
    session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil]; 
    [self addAssetDownload]; 
    // Reset the UI 
    downloading = NO; 
    [self downloadFiles]; 

} 


// Download handler 
- (void)downloadFiles 
{ 
    if ([_assetsToDownload count] > 0) 
    { 
     // Acquire the appropriate downloadTask and respond appropriately to the user's selection 
     NSURLSessionDownloadTask * downloadTask = [_assetsToDownload[0] downloadTask]; 
     if (downloadTask.state == NSURLSessionTaskStateCompleted) 
     { 
      // Download is complete. Play movie. 
      // NSURL *movieURL = [NSURL fileURLWithPath:[_assetsToDownload[0] localPath]]; 
     } 
     else if (downloadTask.state == NSURLSessionTaskStateSuspended) 
     { 
      // If suspended and not already downloading, resume transfer. 
      if (!downloading) 
      { 
       [self showHUD:[NSString stringWithFormat:@"Downloading %@",[_assetsToDownload[0] assetName]]]; 
       [downloadTask resume]; 
       downloading = YES; 
      } 
     } 
     else if (downloadTask.state == NSURLSessionTaskStateRunning) 
     { 
      // If already downloading, pause the transfer. 
      [downloadTask suspend]; 
      downloading = NO; 
     } 

    } 
} 

- (void)downloadAssets 
{ 
    _assets = [self retreiveAssets]; // Getting the resource details from the database 
    if (![_assets count]) 
    { 
     // Hide progress 
    } 
    [self addAssetDownload]; 
    [self downloadFiles]; 
} 
@end 

问题:

有时它下载的第一个文件,并停在那里,下次启动时起,它没有下载任何东西。直到现在我还找不到这个问题,因为这个问题我几乎浪费了一天的时间。请帮我找到问题。提前致谢。

+0

@Rob:感谢您的信息,我会检查它 –

回答

3

使用后台会话时,旧的下载请求可以在会话间持续存在。您是否尝试过使用getTasksWithCompletionHandler检查旧的,出色的后台任务?我有一段时间,直到我意识到,当我的应用程序启动时,它可以积压在旧的后台请求后面。如果您在后台会话中有任何无效请求,则可以对所有内容进行备份。

此外,您的应用程序代表是否正在处理handleEventsForBackgroundURLSession方法,重新实例化后台会话并保存传递到您的应用的completionHandler?你的NSURLSessiondelegate调用完成处理程序(推测在URLSessionDidFinishEventsForBackgroundURLSession:方法中)?你想确保你清理这些背景会话。在代码片段中我没有看到任何这种方法,但为了简洁起见,您可能会忽略它。

对此的讨论可以在URL Loading System Programming Guide: Using NSURLSession指南的背景传输注意事项部分中找到。在WWDC 2013 What’s New in Foundation Networking视频中显示大约40分钟时,还会显示此示例。

0

使用NSURLSessionDownloadTask对我来说是一团糟。所以最后我实现了一个使用NSOperationQueueblocks的自定义下载管理器。

我已将此库添加到GitHub