2013-09-03 12 views
8

私はCollectionViewを内部に持つViewControllerを持っています。ビューがロードされると、可視セル(9セル)が正しく表示されます。下にスクロールすると、partnerCollectionViewのindexPathsForVisibleItemsを呼び出すことによって、loadImagesForOnscreenRowsでcollectionviewの可視アイテムをロードします。しかし、loadImagesForOnscreenRowsを実行すると、indexPathsForVisibleItemsには、セル10〜18を画面に表示する必要がある場合でも、最初の9つのセルが常に存在します。私が使用するコードは、次のとおりUICollectionView indexPathsForVisibleItemsは新しい可視セルを更新しません

#import "PartnerListViewController.h" 
#import "AppDelegate.h" 
#import "Partner.h" 
#import "ImageLoader.h" 
#import "PartnerDetailViewController.h" 

@interface PartnerListViewController() 

@end 

@implementation PartnerListViewController 

@synthesize lblTitle; 
@synthesize partnerCollectionView; 

@synthesize imageDownloadsInProgress; 

@synthesize fetchedResultsController; 
@synthesize managedObjectContext; 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view. 

    AppDelegate * appDelegate = (AppDelegate *) [[UIApplication sharedApplication] delegate]; 
    managedObjectContext = [appDelegate managedObjectContext]; 
    imageDownloadsInProgress = [NSMutableDictionary dictionary]; 
    appDelegate = nil; 

    [self setupFetchedResultsController]; 
    [partnerCollectionView reloadData]; 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

#pragma mark - Collection view data source 

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { 
    return [[fetchedResultsController sections] count]; 
} 

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 
    id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section]; 
    return [sectionInfo numberOfObjects]; 
} 

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    static NSString *CellIdentifier = @"PartnerCell"; 
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:CellIdentifier forIndexPath:indexPath]; 

    Partner *partner = [self.fetchedResultsController objectAtIndexPath:indexPath]; 

    UIImageView *imageView = (UIImageView *)[cell viewWithTag:100]; 
    if (!partner.image) 
    { 
     imageView.image = [UIImage imageNamed:@"annotationMap.png"]; 
     if (self.partnerCollectionView.dragging == NO && self.partnerCollectionView.decelerating == NO) 
     { 
      [self startDownload:partner.imageUrl forIndexPath:indexPath]; 
     } 
    } else { 
     imageView.image = [UIImage imageWithData:partner.image]; 
    } 

    UILabel *lblTitlePartner = (UILabel *)[cell viewWithTag:101]; 
    lblTitlePartner.text = partner.title; 
    lblTitlePartner.font = [UIFont fontWithName:fontName size:10]; 

    return cell; 
} 

#pragma mark - Table cell image support 
- (void)startDownload:(NSString *)urlString forIndexPath:(NSIndexPath *)indexPath 
{ 
    NSLog(@"startDownload:%ld", (long)indexPath.row); 

    ImageLoader *imageLoader = [imageDownloadsInProgress objectForKey:indexPath]; 
    imageLoader = [[ImageLoader alloc] init]; 
    imageLoader.urlString = urlString; 
    imageLoader.indexPathTableView = indexPath; 
    imageLoader.delegate = (id)self; 
    [imageDownloadsInProgress setObject:imageLoader forKey:indexPath]; 
    [imageLoader startDownload]; 
} 

// this method is used in case the user scrolled into a set of cells that don't have their app icons yet 
- (void)loadImagesForOnscreenRows 
{ 
    NSArray *visiblePaths = [self.partnerCollectionView indexPathsForVisibleItems]; 
    NSMutableArray *rowsArray = [NSMutableArray arrayWithCapacity:[visiblePaths count]]; 
    [visiblePaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, BOOL *stop) { 
     NSLog(@"loadImagesForOnscreenRows1%@", @(indexPath.item)); 
     [rowsArray addObject:@(indexPath.item)]; 
    }]; 
    for (NSIndexPath *indexPath in visiblePaths) 
    { 
     NSLog(@"loadImagesForOnscreenRows2:%ld", (long)indexPath.row); 

     Partner *item = [self.fetchedResultsController objectAtIndexPath:indexPath]; 

     if (!item.image) // avoid the app icon download if the app already has an icon 
     { 
      [self startDownload:item.imageUrl forIndexPath:indexPath]; 
     } 
    } 
} 

// called by our ImageDownloader when an icon is ready to be displayed 
- (void)imageLoaderDidFinishDownloading:(NSIndexPath *)indexPath 
{ 
    NSLog(@"imageLoaderDidFinishDownloading:%ld", (long)indexPath.row); 

    ImageLoader *imageLoader = [imageDownloadsInProgress objectForKey:indexPath]; 
    if (imageLoader != nil) 
    { 
     // Save the newly loaded image 
     Partner *item = [self.fetchedResultsController objectAtIndexPath:indexPath]; 
     item.image = UIImageJPEGRepresentation(imageLoader.image, 1.0); 

     [self performSelectorOnMainThread:@selector(saveItem) withObject:nil waitUntilDone:YES]; 
     [self performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:YES]; 
    } 
} 

- (void)saveItem 
{ 
    [self.managedObjectContext save:nil]; 
} 

- (void)reloadData 
{ 
    [self.partnerCollectionView reloadData]; 
} 

#pragma mark deferred image loading (UIScrollViewDelegate) 

// Load images for all onscreen rows when scrolling is finished 
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate 
{ 
    if (!decelerate) 
{ 
     [self loadImagesForOnscreenRows]; 
    } 
} 

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
{ 
    [self loadImagesForOnscreenRows]; 
} 

- (void)setupFetchedResultsController 
{ 
    // 1 - Decide what Entity you want 
    NSString *entityName = @"Partner"; // Put your entity name here 
    NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entityName); 

    // 2 - Request that Entity 
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName]; 

    // 4 - Sort it if you want 
    request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"title" ascending:NO selector:@selector(localizedCaseInsensitiveCompare:)]]; 
    // 5 - Fetch it 
    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil]; 
    NSError *error = nil; 
    if (![[self fetchedResultsController] performFetch:&error]) { 
     NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 
    abort(); 
    } 
} 

@end 

および出力におけるこの結果:

19に項目10にスクロールした後、目に見えるアイテム

2013-09-02 06:45:21.940 [2564:c07] startDownload:0 
2013-09-02 06:45:21.943 [2564:c07] imageLoaderDidFinishDownloading:0 
2013-09-02 06:45:21.950 [2564:c07] startDownload:1 
2013-09-02 06:45:21.951 [2564:c07] imageLoaderDidFinishDownloading:1 
2013-09-02 06:45:21.958 [2564:c07] startDownload:2 
2013-09-02 06:45:21.959 [2564:c07] imageLoaderDidFinishDownloading:2 
2013-09-02 06:45:21.965 [2564:c07] startDownload:3 
2013-09-02 06:45:22.063 [2564:c07] imageLoaderDidFinishDownloading:3 
2013-09-02 06:45:22.072 [2564:c07] startDownload:4 
2013-09-02 06:45:22.073 [2564:c07] imageLoaderDidFinishDownloading:4 
2013-09-02 06:45:22.081 [2564:c07] startDownload:5 
2013-09-02 06:45:22.082 [2564:c07] imageLoaderDidFinishDownloading:5 
2013-09-02 06:45:22.089 [2564:c07] startDownload:6 
2013-09-02 06:45:22.090 [2564:c07] imageLoaderDidFinishDownloading:6 
2013-09-02 06:45:22.098 [2564:c07] startDownload:7 
2013-09-02 06:45:22.099 [2564:c07] imageLoaderDidFinishDownloading:7 
2013-09-02 06:45:22.104 [2564:c07] startDownload:8 
2013-09-02 06:45:22.163 [2564:c07] imageLoaderDidFinishDownloading:8 

初期表示:

2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:8 
2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:0 
2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:1 
2013-09-02 06:45:26.212 [2564:c07] loadImagesForOnscreenRows1:6 
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:2 
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:3 
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:4 
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:5 
2013-09-02 06:45:26.213 [2564:c07] loadImagesForOnscreenRows1:7 
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:8 
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:0 
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:1 
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:6 
2013-09-02 06:45:26.214 [2564:c07] loadImagesForOnscreenRows2:2 
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:3 
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:4 
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:5 
2013-09-02 06:45:26.215 [2564:c07] loadImagesForOnscreenRows2:7 

スクロール後にわかるように、目に見えるインデックスパスは同じままです。他に誰かがこの問題や解決策のアイデアに遭遇しましたか?あるいは私はcollectionviewの何らかの原則を間違っていますか?

事前に感謝します。 敬具、 月

+0

私は 'loadImagesForOnscreenRows'の目的を持っていません。 'cellForRowAtIndexPath'では、画像が利用可能であれば設定します。さもなければ、 'imageLoaderDidFinishDownloading'で' cellForRowAtIndexPath'を再度呼び出すインデックスパスをリロードすることができます。また、画面上にまだ画像がある場合は、直接セル上にイメージを設定することができます。それはそれをカバーしないだろうか? –

+0

こんにちはTimothy、 'cellForRowAtIndexPath'は、私の場合は最初の9個のビューで見えるセルを読み込みます。私がスクロールを開始すると、今後のセルは埋め込まれず、 'scrollViewDidEndDragging'が呼び出され、tableviewsのように' loadImagesForOnscreenRows'が呼び出されます。この関数では、表示可能なインデックスパス 'indexPathsForVisibleItems'を取得し、イメージのダウンロードを開始します。これらがダウンロードされると、indexpathをリロードします。しかし、 'indexPathsForVisibleItems'は常に最初の9個を返します。あるいは、何かを完全に間違ってやっていますか?テーブルでは、このようにうまく動作します。 –

+0

イメージを持たないセルは、通常、そのセルのダウンロードが完了すると個別に入力されます。この場合、 'imageLoaderDidFinishDownloading'で発生します。これを考えると、私は 'loadimageforOnscreenRows'のポイントを得ていません。言い換えれば、 'imageLoaderDidFinishDownloading'でセルを埋めていないのはなぜですか? –

答えて

5

あなたはiOSの8.0をターゲットにしている場合、あなたはあなたのダウンロードをキックオフするcollectionView:willDisplayCell:forItemAtIndexPath:を使用する必要があります上記の。 iOS 7.0をご使用の場合は、引き続きcollectionView:cellForItemAtIndexPath:を使用してください。

imageLoaderDidFinishDownloading:コールバックでは、問題のインデックスパスが引き続き表示されるかどうかを確認する必要があります。一致する場合は、対応するセルを取得して、そのイメージビューを更新します。セルが表示されていない場合、作業は完了です。あなたのユーザーが現在テーブルの真ん中をスクロールしていて、その内容をリセットした場合、画像完成ごとに-reloadDataを呼び出すことは費用のかかる仕事をたくさんしており、かなりのUXの問題を引き起こす可能性があります。 UIImageJPEGRepresentation()の作業を何度も行っている可能性もあります。この作業をimageLoaderDidFinishDownloading:で1回実行した後にスクロールしてパフォーマンスを向上させると、キャッシュされます。

バックグラウンドスレッドでコールバックが発生するように見えるので、メインスレッドからUICollectionViewを操作するようにしてください。

関連する問題