2011-10-24 10 views
1

通常のUITableView + asyncのダウンロード+キャッシュ手法の独自の風味を引き出そうとしています。私がやっていることはcellForRowAtIndexPathでデキューます各セルのために、次のとおりです。UITableViewCell画像を取得して、UITableViewをスクロールせずにダウンロードした画像に更新する方法

1-Check if it's corresponding thumbnail image is already 'cached' in /Library/Caches 
2-If it is, just use that. 
3-If not, load a default image and enqueue an NSInvocationOperation to take care of it: 
    4a-The NSInvocationOperation gets the image from a remote server 
    4b-Does the UIGraphicsBeginContext thing to scale down the image to 40x40 
    4c-saves the scaled down version to /Library/Cache 
    4d-'SHOULD' update the cell's image to the new downloaded and downsized image, if the cell is still visible. 

しかし、私は手動でバックスクリーンにそれらをオフにスクロールしない限り、細胞がそれらのイメージを更新するために取得する方法を見つけ出すことはできません。私が引き出すことができた唯一のハックは、performSelectorOnMainThreadによってNSOperationがメインスレッドを呼び出すことです。メインスレッドは[viewtable reloadData]を呼び出すことができます。しかし、これは無駄に思えます。セルの新しいイメージが準備されるたびに、テーブル全体をリロードしています。

私は主スレッドにブールフラグを設定してから、scrollViewDidEndDeceleratingを実行すると、フラグが設定されていれば[viewtable reloadData]が呼び出されます。このアプローチでは、ユーザーがスクロールを完了したときにセルがリフレッシュされます。

しかし、キャッシュされた画像がまだ表示されている間は、表示されているセルのみを更新することができます(ユーザーがビューからスクロールしなかったことを意味します)。

はここに、これまでに私のコードです:NSInvocationOperationの「カーネル」については

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"Cell"; 

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 
    if (cell == nil) 
    { 
    cell = [[[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle 
            reuseIdentifier: CellIdentifier] autorelease]; 

    cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 
    cell.selectionStyle = UITableViewCellSelectionStyleGray; 
    } 

    // Configure the cell... 
    cell.textLabel.text = [[dbData objectAtIndex:indexPath.row] objectAtIndex:0]; 
    cell.detailTextLabel.text = [[dbData objectAtIndex:indexPath.row] objectAtIndex:1]; 

    NSString *ImageName = [[dbData objectAtIndex:indexPath.row] objectAtIndex:2]; 
    NSString *cachedImageName = [[[ImageName stringByDeletingPathExtension] stringByAppendingString:thumbnailSizeSuffix] stringByAppendingPathExtension:@"png"]; 
    NSString *cachedImagePath = [cachePath stringByAppendingPathComponent:cachedImageName]; 

    if([[NSFileManager defaultManager] fileExistsAtPath:cachedImagePath]) 
    cell.imageView.image = [UIImage imageWithContentsOfFile:cachedImagePath]; 
    else 
    { 
    cell.imageView.image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:defaultNeedsDownloadIconFile ofType:@"png"]]; 
    NSArray *package = [NSArray arrayWithObjects:ImageName, cachedImagePath ,referencingTable, nil];          
    NSInvocationOperation *concurrentImageLoader = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadURI:) object:package]; 
    [concurrentQueue addOperation: concurrentImageLoader]; 
    [concurrentImageLoader release]; 
    } 

    return cell; 
} 

、私はこれ試してみた:

- (void)loadURI:(id)package 
{ 
    NSArray *payload = (NSArray*)package; 

    NSString *imageName = [payload objectAtIndex:0]; 
    NSString *cachedImagePath = [payload objectAtIndex:1]; 
    NSString *imageURL = [NSString stringWithFormat:@"http://www.useanddisposeof.com/VentanaSurDB/%@/photo/%@",[payload objectAtIndex:2], imageName]; 

    UIImage *newThumbnail = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]]]; 

    if(!newThumbnail) 
    newThumbnail = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:defaultNotFoundIconFile ofType:@"png"]]; 

    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, thumbnailSize.width, thumbnailSize.height)]; 
    imageView.layer.borderColor = [UIColor blackColor].CGColor; 
    imageView.layer.cornerRadius = 4.0; 
    imageView.layer.masksToBounds = YES; 
    imageView.layer.borderWidth = 1.0; 
    imageView.image = newThumbnail; 

    UIGraphicsBeginImageContext(CGSizeMake(thumbnailSize.width, thumbnailSize.height)); 
    [imageView.layer renderInContext:UIGraphicsGetCurrentContext()]; 
    newThumbnail = UIGraphicsGetImageFromCurrentImageContext();  
    UIGraphicsEndImageContext(); 

    [imageView release]; 
    [UIImagePNGRepresentation(newThumbnail) writeToFile:cachedImagePath atomically:YES]; 
    [self performSelectorOnMainThread:@selector(updateCellImage) withObject:nil waitUntilDone:NO]; 
} 

をそして、これはバックのためにメインスレッド内のコードですテーブルビューをリフレッシュする:

- (void)updateCellImage:(id)package 
{ 
    needReloadCachedImages = YES; 
} 

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
{ 
    // I know, I know, there's a race condition here.. I'll fix it if this code stays. 
    if(needReloadCachedImages) 
    [self.tableView reloadData]; 

    needReloadCachedImages = NO; 
} 

アイデアをお持ちですか?

答えて

2

しかし、これは無駄に思えます。 セルの新しいイメージが準備完了するたびに、テーブル全体がリロードされます。

reloadDataは、テーブル全体ではなく、目に見えるセルだけをリロードします。

+0

ああ私はそれを知らなかった。私は問題はそれがまだスクロールダウンが遅いということだと思う。ビューを更新しながらテーブルをスムーズにスクロールさせる方法があるのだろうかと思います。 – SaldaVonSchwartz

2

いくつか与えるのはいかがですかopen-sourcetry?これは単純な問題のためにはあまりにも多くの努力をしています。これにはa nice tutorialもあります。これは、あなたが間違っていると思われることをあなたに知らせるかもしれません。

+0

私はあまりにも多くの努力だとは思わない。 '良いチュートリアル'は、同じスレッドだけがNSURLConnection(スレッドにまたがる)に隠されているだけです。チュートリアルで気づいた重要な違いは、サブクラス化が必要なことです。つまり、コールバックがビュー内で発生し、ビュー自体がリロードされる可能性があります。そうすれば、私はreloadDataを混乱させることはありません。 – SaldaVonSchwartz

+0

Appleの例であるLazyTableImagesもあります。これは本当に価値のあるものです。 –

関連する問題