Cocoa touch NSURLSessionDownloadTask并发下载,在应用程序后台也受支持,未按预期工作

Cocoa touch NSURLSessionDownloadTask并发下载,在应用程序后台也受支持,未按预期工作,cocoa-touch,concurrency,nsurlsessiondownloadtask,Cocoa Touch,Concurrency,Nsurlsessiondownloadtask,要求: 我有一个视图控制器类,在其中我显示了一个集合视图。在每个单元格中,我检查图像是否已经存在于本地,如果它不存在,则尝试从服务器下载图像并显示相同的图像 实施: 以下是相同的代码: - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { // retrieving associated pr

要求:

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

实施:

以下是相同的代码:

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

}
在上面的方法中,我将successHandler和failureHandler块存储在字典中,并使用其任务标识符将其映射到下载任务

以下是DidFinishDownloadingTour方法的实现:

- (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,并且当我尝试调用处理程序块时,应用程序崩溃

现在我的问题是:

为什么在DidFinishDownloadingTour中,我得到的标识符与在setupAndStartDownloadTaskForProduct中启动的标识符不同

如果这是预期的行为,那么实现我的需求的最佳方式是什么

您是否已签出将图像延迟加载到UITableView中

也许您可以为UICollectionView定制它

希望这有帮助

您是否已签出将图像延迟加载到UITableView中

也许您可以为UICollectionView定制它


希望这有帮助

您使用的taskIdentifier显然是一个整数。您所做的是使用NSNumber作为具有文字快捷方式的键:

NSNumber*key=@downloadTask.taskIdentifier

问题是,在字典中使用NSString以外的任何东西作为键都不是一个好主意。您所做的是创建一个NSNumber对象,该对象具有相同的值,但不保证-isEqual:的计算结果为true

将密钥转换为字符串,而不是使用NSNumber密钥:

NSString*键=[NSString stringWithFormat:@%d,downloadTask.taskIdentifier]


然后字典散列将起作用。

您使用的taskIdentifier显然是一个整数。您所做的是使用NSNumber作为具有文字快捷方式的键:

NSNumber*key=@downloadTask.taskIdentifier

问题是,在字典中使用NSString以外的任何东西作为键都不是一个好主意。您所做的是创建一个NSNumber对象,该对象具有相同的值,但不保证-isEqual:的计算结果为true

将密钥转换为字符串,而不是使用NSNumber密钥:

NSString*键=[NSString stringWithFormat:@%d,downloadTask.taskIdentifier]


然后字典散列将起作用。

你能为self.session发布你的代码吗?你能为self.session发布你的代码吗?该链接与海报使用的是严重的倒退。该链接与海报使用的是严重的倒退。