如何判断文件何时完成下载并准备使用?

时间:2017-09-14 08:30:39

标签: objective-c cocoa-touch nsurlconnection

我正在从我自己的网络服务下载一个文件(.json),当它完成下载后,我需要将内容解压缩到#39;进入本地SQLlite数据库。

我认为NSURLConnection在另一个线程上异步下载文件以保持主线程打开。问题是,当文件下载开始时,主线程显然继续做它正在做的事情 - 在这种情况下试图将文件的内容加载到数据库中。到发生这种情况时,文件还不存在或存在但尚未完成。

如何在文件实际完全下载并准备好使用后,运行将文件内容输入数据库的方法?

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

将文件保存到数据库的方法:

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

为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);
}

2 个答案:

答案 0 :(得分:1)

我会坚持使用NSURLSession和NSURLSessionDownloadTask,因为不推荐使用NSURLConnection。

NSURLSessionDownloadTask可以在一个块或一个委托中回答,让我们坚持使用块变体。

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

任务在完成或失败时调用其阻止。 tempLocation上的文件只是临时的,之后会被删除,如果你想保留它,你需要将它移动到不同的路径。

有关详细信息,您可以阅读使用NSURLSession + Tasks

的Apple文档

答案 1 :(得分:0)

如果使用NSURLSessionDownloadTask,它将更容易处理,因为它是一个完成块方法。完成下载后,将执行块中的代码。另外,NSURLConnection已被弃用。