2

要件:

コレクションビューを表示しているView Controllerクラスがあります。セルごとに、画像がローカルに既に存在するかどうかを確認しています。存在しない場合は、サーバーから画像をダウンロードして同じものを表示しようとしています。

実装:

以下は同じコードです。

- (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 ブロックをディクショナリに格納し、タスク識別子を使用してダウンロード タスクにマッピングしています。

以下は、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. didFinishDownloadingToURL で、setupAndStartDownloadTaskForProduct で開始されたものとは異なる識別子を取得するのはなぜですか?

  2. これが予想される動作である場合、私の要件を実装する最良の方法は何ですか?

4

2 に答える 2

-1

UITableView への画像の遅延読み込みに関するこの投稿をチェックしましたか?

UICollectionView用にカスタマイズできるかもしれません。

お役に立てれば!

于 2014-02-05T12:11:49.140 に答える