UICollectionView indexPathsForVisibleItems nicht aktualisieren, neue sichtbare Zellen

Ich habe einen ViewController mit einem CollectionView im inneren. Wenn die Ansicht geladen wird, die sichtbaren Zellen (9 Zellen) werden korrekt angezeigt. Wenn ich nach unten scrollen, will ich laden Sie die sichtbaren Elemente in der collectionview mit loadImagesForOnscreenRows durch den Aufruf der indexPathsForVisibleItems für partnerCollectionView. Aber wenn loadImagesForOnscreenRows die indexPathsForVisibleItems hat immer die ersten 9 Zellen, auch dann, wenn die Zellen 10 bis 18 sollte auf dem Bildschirm sichtbar. Der code, den ich verwenden ist:

#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

Und das Ergebnis in der Ausgabe:

Erste Karte sichtbaren Elementen

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

Nach dem scrollen zu Artikel 10 um 19:

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

Wie Sie sehen können nach dem scrollen werden die Elemente sichtbar, index-Pfade bleiben gleich. Hat sonst jemand Probleme oder eine Idee für eine Lösung? Oder bin ich unsterstanding einige Prinzip der collectionview falsch?

Vielen Dank im Voraus!
Mit freundlichen GRÜßEN,
Jan

  • Ich habe nicht den Zweck loadImagesForOnscreenRows. In cellForRowAtIndexPath Sie das Bild, wenn es verfügbar ist. Ansonsten, in imageLoaderDidFinishDownloading laden Sie die index-Pfad, die rufen cellForRowAtIndexPath wieder oder Sie können das Bild auf die Zelle direkt, ob es noch auf dem Bildschirm. Wäre das nicht abdecken?
  • Hallo Timothy, cellForRowAtIndexPath lädt die Zellen, die in der Ansicht sichtbar sind, in meinem Fall die ersten neun. Wenn ich anfange zu scrollen, das kommende Zellen nicht ausgefüllt werden, statt scrollViewDidEndDragging genannt wird, rufen loadImagesForOnscreenRows wie in tableviews. In dieser Funktion möchte ich, um die indexpaths, indexPathsForVisibleItems, sichtbar sind, und starten Sie das herunterladen der Bilder, sobald diese heruntergeladen sind, laden Sie die indexpaths. Aber indexPathsForVisibleItems gibt immer den ersten neun. Oder mache ich etwas komplett falsch. Mit Tabellen funktioniert es auf diese Weise.
  • Die Zellen, die nicht über Bilder würden in der Regel erhalten Sie individuell ausgefüllt, wenn der download für die Zelle abgeschlossen ist, was in deinem Fall passieren würde, in imageLoaderDidFinishDownloading. Angesichts dieser, ich weiß nicht, was der Punkt von loadimageforOnscreenRows. In anderen Worten, warum sind Sie nicht ausfüllen in der Zelle, in imageLoaderDidFinishDownloading?
  • Wenn ich die Last meiner Sicht cellForRowAtIndexPath wird nur aufgerufen, für die ersten neun Zellen, die sichtbaren sind. Ein NSLogim cellForRowAtIndexPath druckt nur 0 bis 8. Damit die anderen Zellen nicht den Download starten, Neuladen der collectionView nach Holen das Ergebnis wirkt sich nur auf die sichtbaren Zellen. Das ist, warum ich lehrte ich es nennen soll loadimageforOnscreenRows auf scrollViewDidEndDragging, so kann das laden der Bilder für die Zellen, die sichtbar nach unten scrollen. Weil wenn ich die scrollViewDidEndDragging im Kommentar, es tut sich nichts nach dem scrollen. 🙂
  • cellForRowAtIndexPath wird immer aufgerufen, bevor eine Zelle auf dem Bildschirm angezeigt wird. Sonst würde nichts angezeigt. Auch, Sie scheinen es nicht zu sein, die Umsetzung der NSFetchedResultsControllerDelegate Methoden, so bin ich mir unklar, warum man selbst mit einer NSFetchedResultsController da, ohne einen Delegaten, es ist keine Kontrolle, nichts. Bin ich etwas fehlt?
  • Hallo Timothy, ich habe ein anderes problem. Mit reloadData auf den collectionview in imageLoaderDidFinishDownloading nicht nennen cellForRowAtIndexPath für die Zellen sichtbar werden. Wenn ich reloadItemsAtIndexPaths, cellForRowAtIndexPath genannt wird, für die Zellen sichtbar werden. Das problem ist nur, dass die erste Zelle jeder Zeile hält seine Standard-Bild-und die anderen sind erfrischt richtig. Wenn ich scroll die ersten Zellen aus dem Bildschirm heraus-und wieder an, erscheinen Sie richtig. So der download ist richtig, nur erfrischend scheint nicht zu funktionieren. Haben Sie eine Idee? Vielen Dank im Voraus!
  • indexPathsForVisibleItems scheint zurück ein Array von Elementen in der vertikalen Ordnung. Zum Beispiel, wenn Sie 3 Spalten in der UICollectionView, indexPathsForVisibleItems zurück, die sichtbaren Elemente in der ersten Spalte (0, 3, 6). Dann, in der zweiten Spalte (1, 4, 7). Schließlich, die Dritte Spalte (2, 5, 8). Das bedeutet, dass Sie Ihre Bestellung zurückgegeben werden 0, 3, 6, 1, 4, 7, 2, 5, 8 die funktioniert etwas anders als ein tableview zurückgeben würde 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. Wenn Sie wirklich brauchen, um das laden der Bilder in der horizontalen Reihenfolge, Sortieren Sie das array zurückgegeben, bevor Sie fortfahren.

InformationsquelleAutor Jan Stulens | 2013-09-03
Schreibe einen Kommentar