使用NSURLConnection进行异步下载证明不可靠

时间:2015-01-21 07:41:55

标签: ios core-data asynchronous download nsurlconnection

我一直在使用NSURLConnection来执行一些异步下载。基本上我从Parse后端检索PFFile并在Web视图中显示它。我提供了下载到设备的选项。一切都很好,所有任务都按要求执行,但是,最近我注意到,如果我以高速执行下载,其中一些不会出现在下载VC中。我不知道如何测试它,但我的理论是它因为优先级设置为高,即使而被切断,用户无法做任何事情直到下载完成。您必须退出当前UIWebView以选择其他文档。这不是一种组合行为,这使我更难以缩小范围。它只发生在我下载>退出>打开> &安培;立即下载另一个文档>退出>重复完成,没有特定的文件。

问题 :下载执行,我创建了一个NSLog文件,但是,当我转到下载VC时,文档没有显示出来在NSFRC中,但仍显示为目录中的有效文件。

过程 如何下载,

UIWebView加载从Parse.com查询的PDF。这里没问题。 ProgressHUD显示

加载后,progressHUD就会消失。

如果他们想要下载PDF,只需点击操作表索引进行下载,即可开始下载。

您可以在NSURL didReceiveData显示中看到另一个进度HUD。在下载完成之前,此HUD不允许用户交互。因此,您无法退出View Controller以选择其他pdf,直到完成下载完成为止。所以 NO 我没有同时进行大量下载,一次只下载一次。

然后用户可以在下载完成后退出,选择另一个加载相应PDF的UITableViewCell并重复该过程。

加载PDF:

PFQuery *EGQuery = [PFQuery queryWithClassName:@"Classname"];
    [EGQuery whereKey:@"KeyName" equalTo:self.title];
    [EGQuery getFirstObjectInBackgroundWithBlock:^(PFObject *object, NSError *error) {
        if (!error) {
            if ([object objectForKey:@"EGFile"]) {
                PFFile *file = [object objectForKey:@"EGFile"];
                self.pdfURL = [file url];
                self.pdfName = [file name]; //Ends up as EG_2014_04 this is what I append to the filePath where it's stored so the filePath will be /PDFs/EG_2014_04
                [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.pdfURL]]];
            } else {
            }

下载方法:

        NSManagedObjectContext *context = [self managedObjectContext];
        NSError *error = nil;
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Downloads"];
        [request setPredicate:[NSPredicate predicateWithFormat:@"pubnumber = %@", self.title]];
        [request setFetchLimit:1];
        NSUInteger count = [context countForFetchRequest:request error:&error];
        if (count == NSNotFound) {

        } else if (count == 0) {

            NSURL *url = [NSURL URLWithString:pdfURL]; //pdfURL is PFFile url
            NSURLRequest *request = [NSURLRequest requestWithURL:url];
            NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];

            dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
            dispatch_async(queue, ^{
               self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
                    [connection start];
                    NSLog(@"Background time remaining = %.1f seconds", [UIApplication sharedApplication].backgroundTimeRemaining);
               }];
                NSData *pdfData = [[NSData alloc]
                                   initWithContentsOfURL:[NSURL URLWithString:self.pdfURL]];

                NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
                NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:@"PDFs"];
                NSString *filePath = [path stringByAppendingPathComponent:self.pdfName];

                NSFileManager *fm = [NSFileManager defaultManager];
                [fm createFileAtPath:filePath contents:pdfData attributes:nil];
                if ([fm createFileAtPath:filePath contents:pdfData attributes:nil])
                {
                    dispatch_async(dispatch_get_main_queue(), ^{
                    NSManagedObject *newDWNLD = [NSEntityDescription insertNewObjectForEntityForName:@"Downloads" inManagedObjectContext:context];
                    [newDWNLD setValue:self.title forKey:@"pubnumber"];
                    [newDWNLD setValue:self.pubTitle forKey:@"pubtitle"];
                    [newDWNLD setValue:self.pdfName forKey:@"puburl"]; // this is what I use for the file path name in the PDF directory and this is how I call it in my NSFRC
                    });
                    NSLog(@"File was created");
                } else {
                    NSLog(@"File not created");
                }
            });

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    expectedLength = MAX([response expectedContentLength], 1);
    currentLength = 0;
    HUD.dimBackground = YES;
    HUD.mode = MBProgressHUDModeAnnularDeterminate;
    HUD.labelText = @"Downloading...";
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
currentLength += [data length];
HUD.progress = currentLength / (float)expectedLength;
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"success.png"]];
HUD.mode = MBProgressHUDModeCustomView;
HUD.labelText = @"Success!";
HUD.detailsLabelText = @"Added to Downloads";
HUD.dimBackground = YES;
[HUD hide:YES afterDelay:1.6];
//Cancel Background task if completed
//[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
//self.backgroundTask = UIBackgroundTaskInvalid;
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Error %@", error);
[HUD hide:YES];
}

下载VC

- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController != nil) {
    return fetchedResultsController;
}

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];

NSEntityDescription *entity = [NSEntityDescription entityForName:@"Downloads" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];


[fetchRequest setFetchBatchSize:50];

NSSortDescriptor *azSort = [[NSSortDescriptor alloc] initWithKey:@"pubnumber" ascending:YES];
NSArray *azSortArray = @[azSort];

[fetchRequest setSortDescriptors:azSortArray];

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"pubnumber" cacheName:nil];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;

NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}

return fetchedResultsController;
}

cellForRowAtIndexPath:

NSString *title = [NSString stringWithFormat:@"%@", [context valueForKey:@"pubnumber"]];
cell.textLabel.text = title;
etc etc

编辑它似乎下载了所有这些内容,并且'创建'一个文件,但它不会在VC中显示所有文件。

application DidFinishLaunchingWithOptions:

NSString *createPaths;
NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
createPaths = [[documents objectAtIndex:0] stringByAppendingPathComponent:@"PDFs"];
 NSLog(@"PDFs directory: %@", [[NSFileManager defaultManager] contentsOfDirectoryAtPath:createPaths error:&error]);

上面记录了我下载的所有文件,但它们不是从UIWebView中被识别为完全下载的,或者在下载过程中以某种方式创建文件路径是错误的,所以它是不显示在下载视图控制器中,但其他文档确实显示。每次会议一直缺1-2次,但就像我之前说过的那样,它从来没有丢失过相同的文件,所以缺少任何感觉缺失的东西。假设我下载10然后关闭应用程序然后重新打开它9只会在下载VC中有时8,但它会在目录中记录为有效的filePath。

1 个答案:

答案 0 :(得分:1)

问题似乎是您的托管对象上下文线程限制,特别是您没有限制。你得到原始线程的上下文,可能是主线程,但是你在后台块中捕获它并直接访问它。

您应该保存文件并将其发送回主线程,然后在那里创建并保存新的托管对象。