2014-09-10 3 views
5

Я хочу загрузить список файлов с помощью NSUrlSession.iOS 7 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; 
     } 
    }]; 

}

Все работает отлично, но когда я снова открыть ViewController, я получаю сообщение A background URLSession with identifier com.myApp already exists!. Счетчик не установлен в 0, и элементы пользовательского интерфейса (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]; 
} 

Когда я нажимаю Download Button я называю этот метод ( У меня есть Downloadable объект, который содержит 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; 
     } 
    } 
} 

Когда приложение находится в Справочная информация:

-(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]; 

       }]; 
      } 
     } 
    }]; 
} 
+0

В настоящее время я изучаю это тоже ... проблема заключается в идентификаторе сеанса - они должны быть уникальными для каждой последующей задачи. В соответствии с этим текстом << Примечание: вы должны создать ровно один сеанс на идентификатор (указанный при создании объекта конфигурации). Поведение нескольких сеансов с одним и тем же идентификатором не определено. >> с этой страницы: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html –

+0

Я думаю, есть два варианта, которые я могу увидеть: 1) скомпилировать все в zip-файл, загрузить этот один файл, затем разархивировать его на стороне клиента (телефона) - или 2) Создать NSMutableArray задач, который добавляет новый фоновый сеанс с уникальным идентификатором для каждого файла во время выполнения. –

+0

В этом учебнике есть предпосылка для нескольких файлов: http://code.tutsplus.com/tutorials/working-with-nsurlsession-part-3--mobile-21879 –

ответ

3

Итак, как я уже упоминал в своих комментариях, проблема в том, что для каждого файла требуется уникальная NSURLSession, и для каждой NSURLSession требуется NSURLSessionConfiguration с уникальным идентификатором.

Я думаю, что вы были близки - и, вероятно, более уместны, чем я, в определенных аспектах ... Вам просто нужно создать структуру для передачи уникальных идентификаторов в уникальные конфигурации, чтобы заполнить уникальные сеансы (скажем, что 10x быстро).

Вот что я сделал:

/* * Получает список файлов для загрузки * Также использует размер этого списка для создания экземпляра элементов * В моем случае, я загружаю персонаж вернулся текстовый файл с имена файлов, которые я хочу, чтобы загрузить */

- (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]; 
} 

/* * Устанавливают Массивы конфигураций и сессии для надлежащего размера * Это также дает уникальный идентификатор для каждого */

- (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]; 
} 

/* * Это устанавливает задачу загрузки для каждого файла, основываясь от индекса массива * Он также сцепляет путь к действительному файлу */

- (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]; 

} 

/*/* * Наконец, в моем методе делегата, после завершения загрузки (после того, как файл перемещен из временных данных), я проверю, завершен ли я, и если не вызвал метод 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 
    } 
} 
Смежные вопросы