2017-09-14 5 views
0

Je télécharge un fichier (.json) à partir de mon propre service Web et lorsque le téléchargement est terminé, j'ai besoin que le contenu soit «décompressé» dans une base de données SQLlite locale.Comment savoir quand le fichier a été téléchargé et prêt à être utilisé?

Je comprends que NSURLConnection télécharge le fichier de façon asynchrone sur un autre thread pour garder le thread principal ouvert. Le problème est que lorsque le téléchargement du fichier a commencé, le thread principal, évidemment, continue à faire ce qu'il fait - dans ce cas, essayer de charger le contenu du fichier dans la base de données. Au moment où cela arrive le fichier n'existe pas encore OU existe mais n'est pas encore complet.

Comment puis-je exécuter la méthode qui saisit le contenu du fichier dans la base de données uniquement APRÈS que le fichier ait été entièrement téléchargé et prêt à être utilisé?

-(void)downloadTheFileFrom:(NSString*)url withToken:(NSString*)token 
{ 
    NSString *conURL = [NSString stringWithFormat:@"%@/%@", apiURL, url]; 
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:conURL]]; 
    [request setHTTPMethod:@"GET"]; 

    [request addValue:@"application/json" forHTTPHeaderField:(@"content-type")]; 
    [request addValue:token forHTTPHeaderField:(@"X-TOKEN")]; 
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; 

    [conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 

    [conn start]; 
    [self saveJsonToDatabase]; 
} 

méthode qui enregistre le fichier dans la base de données:

-(void)saveJsonToDatabase 
{ 
    NSString *jsonFileToSave = @"drug.json"; 
    NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; 
    NSError *jsonError = nil; 

    NSString *jsonFile = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:@"/content/formulary/files/%@", jsonFileToSave]]; 
    NSData *jsonData = [NSData dataWithContentsOfFile:jsonFile]; 
    NSArray *jsonArray = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonError]; 

    NSString *formularyTable = [NSString stringWithFormat:@"formulary_%@", [jsonFileToSave stringByDeletingPathExtension]]; 

    FormularyDBManager *formularyDBManagerInstance = [FormularyDBManager new]; 
    [formularyDBManagerInstance insertInto:formularyTable arrayOfDicts:jsonArray]; 
} 

méthodes de délégué pour NSURLConnection:

-(void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse *)response { 
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; 

    NSString *apiUrl = [NSString stringWithFormat:@"%@",[response URL]]; 
    NSArray *pathComponents = [apiUrl pathComponents]; 
    NSString *areaFolder = [pathComponents objectAtIndex:3]; 
    NSString *fileName = [response suggestedFilename]; 
    NSString *fileType = [fileName pathExtension]; 

    NSString *docsfolderPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; 
    NSString *folderPath = [docsfolderPath stringByAppendingString:[NSString stringWithFormat:@"/content/%@/%@", areaFolder, contentType]]; 

    BOOL isDir; 
    NSFileManager *fileManager= [NSFileManager defaultManager]; 
    if(![fileManager fileExistsAtPath:folderPath isDirectory:&isDir]) 
     if(![fileManager createDirectoryAtPath:folderPath withIntermediateDirectories:YES attributes:nil error:NULL]) 
      NSLog(@"FileDownloader - connection - Error: Create folder failed %@", folderPath); 

    NSString *filePath = [folderPath stringByAppendingPathComponent:fileName]; 

    [[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]; 
    connection.file = [NSFileHandle fileHandleForUpdatingAtPath:filePath]; 

    _currentFile = fileName; 
} 
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 
    [connection.file writeData:data]; 
} 
-(NSCachedURLResponse *)connection:(FileURLConnection *)connection willCacheResponse:(NSCachedURLResponse*)cachedResponse { 
    return nil; 
} 
-(void)connectionDidFinishLoading:(NSURLConnection *)connection 
{ 
    [connection.file closeFile]; 
} 
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 
    NSLog(@"GetData - connection - error - %@", error); 
} 

Répondre

1

Je voudrais coller avec NSURLSession et NSURLSessionDownloadTask depuis NSURLConnection est obsolète.

Un NSURLSessionDownloadTask peut répondre dans un bloc ou à un délégué, permet de s'en tenir à la variante de bloc.

// Your request 
NSString *conURL = [NSString stringWithFormat:@"%@/%@", apiURL, url]; 
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:conURL]]; 
[request setHTTPMethod:@"GET"]; 

[request addValue:@"application/json" forHTTPHeaderField:(@"content-type")]; 
[request addValue:token forHTTPHeaderField:(@"X-TOKEN")];  

// Create a simple Session 
NSURLSession *session = [NSURLSession sharedSession]; 
// Create the downloadTask 
NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable tempLocation, NSURLResponse * _Nullable response, NSError * _Nullable error) { 
    // this block will be called on a async thread when the task is finished. 
    // if no error occurred and we got a path lets store the data. 
    if (!error && tempLocation) { 
     // I pass the location to your function, so it can read the file. 
     [self saveJsonToDatabase:tempLocation]; 
    } 
}]; 
[downloadTask resume]; // don't forget to start the task. 

La tâche appelle son bloc lorsqu'elle est terminée ou a échoué. Le fichier sur tempLocation est seulement temporaire et sera supprimé par la suite, si vous voulez le conserver, vous devez le déplacer vers un chemin différent.

Pour plus de détails, vous pouvez lire la documentation de pomme pour l'utilisation NSURLSession + Tasks

+0

Cela ressemble à cela pourrait adapter ce que je cherche. Puis-je définir où les fichiers seront sauvegardés? J'utilise cette classe pour sauvegarder tout un tas de fichiers, c'est seulement un couple que je dois 'interecter' et mettre leur contenu dans la base de données. – Ryan

+0

Vous pouvez déplacer les fichiers vers un emplacement passé. '[[NSFileManager defaultManager] copyItemAtPath: tempLocation toPath: erreur passedFilePath: nil];' devrait faire l'affaire. – Amset

+0

Après avoir réécrit mon code et ajouté les modifications suggérées, cela fonctionne maintenant comme prévu. Aussi, cette méthode semble beaucoup plus simple que d'avoir à charger des méthodes de délégué à s'inquiéter aussi. Merci! – Ryan

0

Si vous utilisez NSURLSessionDownloadTask il sera plus facile à gérer, car il est une fin méthode de blocage Quand c'est fait, le téléchargement du code dans le bloc sera exécuté. Plus NSURLConnection a été déprécié.