2017-09-14 3 views
0

Ich lade eine Datei (.json) von meinem eigenen Webservice herunter und wenn sie fertig heruntergeladen ist, muss ich den Inhalt in eine lokale SQLlite-Datenbank "entpacken".Wie kann man feststellen, wenn die Datei fertig heruntergeladen wurde und verwendet werden kann?

Ich verstehe, dass NSURLConnection die Datei in einem anderen Thread asynchron herunterlädt, um den Hauptthread geöffnet zu lassen. Das Problem ist, dass, wenn der Datei-Download gestartet wurde, der Haupt-Thread offensichtlich weiter macht, was er tut - in diesem Fall versucht er, den Inhalt der Datei in die Datenbank zu laden. Zu diesem Zeitpunkt existiert die Datei noch nicht ODER existiert, ist aber noch nicht vollständig.

Wie führe ich die Methode aus, die den Inhalt der Datei nur dann in die Datenbank eingibt, NACHDEM die Datei tatsächlich vollständig heruntergeladen und betriebsbereit ist?

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

Methode, die die Datei in die Datenbank speichert:

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

Delegatmethoden für 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); 
} 

Antwort

1

Ich würde mit NSURLSession und NSURLSessionDownloadTask bleiben, da NSURLConnection veraltet ist.

Eine NSURLSessionDownloadTask kann in einem Block oder einem Delegaten antworten, bleiben wir bei der Blockvariante.

// 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. 

Die Task ruft ihren Block auf, wenn sie beendet ist oder fehlgeschlagen ist. Die Datei bei tempLocation ist nur temporär und wird später gelöscht, wenn Sie sie behalten möchten, müssen Sie sie in einen anderen Pfad verschieben.

Für weitere Informationen können Sie den Apfel docs lesen NSURLSession + Tasks

+0

für die Verwendung dieser wie es aussieht, könnte passen, was ich suche. Kann ich festlegen, wo die Dateien gespeichert werden? Ich benutze diese Klasse, um eine ganze Reihe von Dateien zu speichern, es ist nur ein Paar, das ich "interceptieren" und ihren Inhalt in die Datenbank schreiben muss. – Ryan

+0

Sie können die Dateien an einen übergebenen Speicherort verschieben. '[[NSFileManager defaultManager] copyItemAtPath: tempLocation toPath: passedFilePath Fehler: nil];' sollte den Trick machen. – Amset

+0

Nachdem ich meinen Code neu geschrieben und die vorgeschlagenen Änderungen hinzugefügt habe, funktionieren diese jetzt wie beabsichtigt. Außerdem scheint diese Methode sehr einfach zu sein, als dass man sich mit Delegiertenmethoden herumärgern muss. Vielen Dank! – Ryan

0

Wenn Sie NSURLSessionDownloadTask verwenden wird es leichter zu handhaben, da es sich um eine Fertigstellung ist Blockmethode. Nach dem Herunterladen wird der Code im Block ausgeführt. Plus NSURLConnection ist veraltet.

Verwandte Themen