nsurlsessiondowndownloadtask并发下载,在应用程序背景中也支持,无法按预期工作



要求:

我有一个视图控制器类,我在其中显示收集视图。在每个单元格中,我正在检查图像是否已经存在于本地,如果不存在,则我正在尝试从服务器下载图像并显示相同的图像。

实现:

以下是相同的代码:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    // retrieving associated product
    Products *aProduct = [self.fetchedResultsController objectAtIndexPath:indexPath];
    UICollectionViewCell* newCell = [self.collectionView dequeueReusableCellWithReuseIdentifier:kProductIconIdentifier forIndexPath:indexPath];
    // setup of image view and cell label
    UIImageView *cellImageView = (UIImageView *)[collectionView viewWithTag:kImageViewTag];
    cellImageView.contentMode = UIViewContentModeScaleAspectFill;
    UILabel *cellLabel = (UILabel *)[newCell viewWithTag:klabelTag];
    // assigning value to cell label and image view
    NSString *productImageLocalPath = aProduct.imageLocalPath;
    if ([[NSFileManager defaultManager] fileExistsAtPath:productImageLocalPath]) {
        // file exists at local path :-)
        // means less fun :-(
        cellImageView.image = [UIImage imageWithContentsOfFile:productImageLocalPath];
    }
    else
    {
        UIActivityIndicatorView *downloadActivityIndicator = (UIActivityIndicatorView *)[newCell viewWithTag:kActivityIndicator];
        downloadActivityIndicator.hidden = NO;
        [downloadActivityIndicator startAnimating];
        // file does not exist at local path :-(
        // means more fun :-)
        [self.sessionController setupAndStartDownloadTaskForProduct:aProduct withCompletionHandler:^(NSString * tempLocalPath){
            // download was successful
            NSData *imageData = [[NSData alloc] initWithContentsOfFile:tempLocalPath];
            [imageData writeToFile:productImageLocalPath atomically:YES];
            cellImageView.image = [UIImage imageWithData:imageData];
            [downloadActivityIndicator stopAnimating];
        } andFailureHandler:^{
            cellImageView.image = nil;
            [downloadActivityIndicator stopAnimating];
        }];
    }
    // setting values
    cellLabel.text = aProduct.imageName;
    return newCell;
}

在会话控制器类中,我有以下方法来启动新的下载任务:

- (void)setupAndStartDownloadTaskForProduct:(Products *)aProduct withCompletionHandler:(DownloadedCompletionHandler)completionHandler andFailureHandler:(DownloadedFailureHandler)failureHandler
{
    NSString *completeImagePath = [kBasePath stringByAppendingPathComponent:aProduct.imageRelativePath];
    NSURL *downloadURL = [NSURL URLWithString:completeImagePath];
    if (!self.session) {
        [self setUpSession];
    }
    NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:downloadURL];
    NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:downloadRequest];
    NSDictionary *downloadInfoDict = @{kSuccessHandlerKey: [completionHandler copy], kFailureHandlerKey: [failureHandler copy]};
    self.downloadTasks[@(downloadTask.taskIdentifier)] = downloadInfoDict;
    // resuming the download task
    [downloadTask resume];
}

在上面的方法中,我在词典中存储了成功的Handler和Fainhandler块,使用其任务标识符使用下载任务映射。

以下是didfinishDownloadingTourl方法的实现:

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    dispatch_async(dispatch_get_main_queue(), ^{
        // invoking success block
        DownloadedCompletionHandler successCompletionHandler = self.downloadTasks[@(downloadTask.taskIdentifier)][kSuccessHandlerKey];
        successCompletionHandler([location path]);
        // removing download task key-value pair from dictionary
        [self.downloadTasks removeObjectForKey:@(downloadTask.taskIdentifier)];
    });
}

我的问题是 - 有时在上面的方法下downloadtask返回与在setUpandStartDownloadtaskforproduct上发起的标识符不同的标识符,因为在哪个successcompletionhandler中获得了nil,并且当我试图调用处理器块时,应用程序会崩溃。

现在我的问题是:

  1. 为什么在di finishdownloadingtourl中,我得到的标识符与setupandStartDownloadtaskforproduct的启动的标识符不同?

  2. 如果这是预期行为,那么实现我的要求的最佳方法是什么?

您使用的任务识别器显然是Nsuinteger。您正在做的是使用NSnumber作为字面捷径的钥匙:

NSNumber * key = @(downloadTask.taskIdentifier);

问题在于,在字典中使用NSString以外的任何内容是一个坏主意。您所做的是创建一个具有相同值的nsnumber对象,但不能保证-issqual:评估是正确的。

而不是使用nsnumber键,而是将键转换为字符串:

NSString * key = [NSString stringWithFormat:@"%d", downloadTask.taskIdentifier];

然后词典哈希将起作用。

您是否检查了这篇懒惰的图像的帖子?

也许您可以将其自定义为UicollectionView。

希望这会有所帮助!

最新更新