Параллельное соединение NSURLSession с фоновой выборкой iOS 7

Интересно, возможно ли иметь несколько загрузок, когда происходит фоновая выборка (фоновая выборка iOS7). В настоящее время у меня есть приложение, которое загружает данные примерно из 6 RESTful API. Эти вызовы API используют NSURLSession и загружают данные параллельно. Это работает, когда приложение находится на переднем плане. Я реализовал функцию фоновой выборки в своем приложении, где приложение может обновляться, пока оно находится в фоновом режиме. К сожалению, когда происходит фоновая выборка, только первый API вызывается шесть раз. Я очень ценю, если кто-нибудь может помочь мне в этом.

Это код для задач загрузки.

- (void)start {

    self.responseData = [NSMutableData data];
    self.isLoginRequest = YES;

    self.dateFormatter = [[NSDateFormatter alloc] init];
    [self.dateFormatter setDateStyle:NSDateFormatterMediumStyle];

    self.apiList = [NSMutableArray array];

    NSArray *apis = [self fetchAPIData];

    for (API *api in apis) {

        NSString *fullURL = [NSString stringWithFormat:@"%@/%@",BASE_URL, api.url];        

        switch ([api.type integerValue]) {
            case 1:
                [self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestLeadstatus andDownloadSource:fullURL]];
                break;
            case 2:
                [self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestParam andDownloadSource:fullURL]];
                break;
            case 3:
                [self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestLeadprofiles andDownloadSource:fullURL]];
                break;
            case 4:
                [self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestInstallations andDownloadSource:fullURL]];
                break;
            case 5:
                [self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestLeadproviders andDownloadSource:fullURL]];
                break;
            case 6:
                [self.apiList addObject:[[BSJSONInfo alloc] initWithFileType:BSRequestSaleorders andDownloadSource:fullURL]];
                break;                        
            default:
                break;
        }
    }     
    [self startAllDownloads:nil];    
}

- (void)startAllDownloads:(id)sender {

    self.session = [self backgroundSession];

    // Access all download info objects using a loop.
    for (int i=0; i<[self.apiList count]; i++) {
        BSJSONInfo *jsonInfo = [self.apiList objectAtIndex:i];

        // Check if a file is already being downloaded or not.
        if (!jsonInfo.isDownloading) {            
            if (jsonInfo.taskIdentifier == -1) {
                jsonInfo.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:jsonInfo.downloadSource]];
            }
            else{
                jsonInfo.downloadTask = [self.session downloadTaskWithResumeData:jsonInfo.taskResumeData];
            }

            jsonInfo.taskIdentifier = jsonInfo.downloadTask.taskIdentifier;                        
            [jsonInfo.downloadTask resume];            
            jsonInfo.isDownloading = YES;
        }
    }
}

-(int)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier{
    int index = 0;
    for (int i=0; i<[self.apiList count]; i++) {
        BSJSONInfo *jsonInfo = [self.apiList objectAtIndex:i];
        if (jsonInfo.taskIdentifier == taskIdentifier) {
            index = i;
            break;
        }
    }

    return index;
}

- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:[NSString stringWithFormat:@"%@", SESSION_STRING]];
        configuration.timeoutIntervalForRequest = 30.0;
        configuration.timeoutIntervalForResource = 60.0;

        session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];

    });

    return  session;
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL
{    
    NSFileManager *fileManager = [NSFileManager defaultManager];

    NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
    NSURL *documentsDirectory = [URLs objectAtIndex:0];
    NSURL *originalURL = [[downloadTask originalRequest] URL];
    NSURL *destinationURL = [documentsDirectory URLByAppendingPathComponent:[originalURL lastPathComponent]];
    NSError *errorCopy;

    [fileManager removeItemAtURL:destinationURL error:NULL];
    BOOL success = [fileManager copyItemAtURL:downloadURL toURL:destinationURL error:&errorCopy];

    if (success){        
        int index = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
        BSJSONInfo *jsonInfo = [self.apiList objectAtIndex:index];                        
        jsonInfo.isDownloading = NO;
        jsonInfo.downloadComplete = YES;            
        jsonInfo.taskIdentifier = -1;            
        jsonInfo.taskResumeData = nil;            

//Let parser to parse the JSON
        dispatch_async(dispatch_get_main_queue(), ^{

            self.responseData = [NSData dataWithContentsOfURL:destinationURL];
            [self parsingJSONResponse:self.responseData withType:jsonInfo.type];
        });             
    }    
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    if (error != nil) {        
        self.networkError = error;
        [self.delegate downloadingError:[error localizedDescription]];

        dispatch_async(dispatch_get_main_queue(), ^{
            [self.delegate downloadingError:[NSString stringWithFormat:@"%@ for type %lu", [error localizedDescription], self.bsType]];
            return;
        });
    }    
    self.downloadTask = nil;    
}

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
    BSAppDelegate *appDelegate = (BSAppDelegate *)[[UIApplication sharedApplication] delegate];

    // Check if all download tasks have been finished.
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {

        if ([downloadTasks count] == 0) {
            if (appDelegate.backgroundSessionCompletionHandler != nil) {                
                void(^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;

                appDelegate.backgroundSessionCompletionHandler = nil;

                [[NSOperationQueue mainQueue] addOperationWithBlock:^{            
                    completionHandler();

                    UILocalNotification *localNotification = [[UILocalNotification alloc] init];
                    localNotification.alertBody = @"All files have been downloaded!";
                    [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
                }];
            }
        }
    }];    
}

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes{

//    BLog();
}

Спасибо


person Chinthaka    schedule 08.07.2014    source источник
comment
Я использую NSURLSession в производственном приложении и не могу выполнять одновременные загрузки в фоновом сеансе. Может показаться, что в фоновом потоке максимальное количество http-соединений игнорируется. Если вы все равно хотите попробовать, установите HTTPMaximumConnectionsPerHost в объекте NSURLSessionConfiguration.   -  person Grant Amos    schedule 08.07.2014
comment
Спасибо за ответ. Я пробовал и не повезло.   -  person Chinthaka    schedule 08.07.2014


Ответы (1)


Наконец я нашел ответ сам. Если я использую делегата по умолчанию, проблема решена. Боюсь, я не знаю, почему фоновая выборка не работает с пользовательскими делегатами при одновременной загрузке.

    NSURLSession *session = [NSURLSession sharedSession];    
    for (int i=0; i<[self.apiList count]; i++) {
        BSJSONInfo *fdi = [self.apiList objectAtIndex:i];

        NSURLSessionTask *downloadTask = [session downloadTaskWithURL:[NSURL URLWithString:fdi.downloadSource] completionHandler:^(NSURL *url, NSURLResponse *response, NSError *error){

            NSData *d = [NSData dataWithContentsOfURL:url];
            NSDictionary *json = [NSJSONSerialization JSONObjectWithData:d options:0 error:nil];

        }];
        [downloadTask resume];
    }
person Chinthaka    schedule 09.07.2014