2013-09-03 20 views
8

Ho un ViewController con un CollectionView all'interno. Quando la vista viene caricata, le celle visibili (9 celle) vengono visualizzate correttamente. Quando scorro verso il basso, voglio caricare gli elementi visibili nella collectionview con loadImagesForOnscreenRows chiamando l'indicePathsForVisibleItems per partnerCollectionView. Ma quando loadImagesForOnscreenRows indexPathsForVisibleItems ha sempre le prime 9 celle in esso, anche quando le celle da 10 a 18 dovrebbero essere visibili sullo schermo. Il codice che uso è:UICollectionView indexPathsForVisibleItems non aggiorna nuove celle visibili

#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 

e questo risultato in uscita:

spettacolo iniziale di elementi visibili

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 

Dopo lo scorrimento al punto 10 a 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 

Come puoi vedere dopo lo scorrimento, i percorsi degli indici visibili rimangono invariati. Qualcun altro ha incontrato questo o un'idea per una soluzione? O sono in grado di interpretare in modo errato qualche principio di collectionview?

Molte grazie in anticipo! Cordiali saluti, gen

+0

Non ho lo scopo di 'loadImagesForOnscreenRows'. In 'cellForRowAtIndexPath' imposti l'immagine se è disponibile. Altrimenti, in 'imageLoaderDidFinishDownloading' puoi ricaricare il percorso dell'indice, che chiamerà di nuovo' cellForRowAtIndexPath' o puoi impostare l'immagine direttamente sulla cella se è ancora sullo schermo. Non lo coprirebbe? –

+0

Hi Timothy, 'cellForRowAtIndexPath' carica le celle che sono visibili nella vista, nel mio caso le prime nove. Quando comincio lo scorrimento, le celle successive non verranno compilate, ma viene chiamato 'scrollViewDidEndDragging', che chiamerà' loadImagesForOnscreenRows', come in tableviews. In questa funzione voglio ottenere i percorsi index, 'indexPathsForVisibleItems', che sono visibili e iniziare a scaricare le immagini, una volta scaricati, ricaricare i percorsi degli indici. Ma 'indexPathsForVisibleItems' restituisce sempre i primi nove. O sto facendo qualcosa di completamente sbagliato. Con le tabelle funziona così in questo modo. –

+0

Le celle che non dispongono di immagini in genere vengono compilate singolarmente al termine del download per quella cella, che nel tuo caso si verifica in "imageLoaderDidFinishDownloading". Detto questo, non ho capito "loadimageforOnscreenRows". In altre parole, perché non stai compilando la cella in 'imageLoaderDidFinishDownloading'? –

risposta

5

Se si utilizza iOS 8.0 o versione successiva, è necessario utilizzare collectionView:willDisplayCell:forItemAtIndexPath: per avviare il download. Se si utilizza iOS 7.0, è necessario continuare a utilizzare collectionView:cellForItemAtIndexPath:.

Nella callback imageLoaderDidFinishDownloading: è necessario verificare se il percorso dell'indice in questione è ancora visibile. Se lo è, recupera la cella corrispondente e aggiorna la sua visualizzazione dell'immagine. Se la cella non è visibile, allora il tuo lavoro è finito. Chiamare -reloadData per ogni completamento dell'immagine sta facendo un sacco di lavoro costoso e potrebbe avere problemi UX significativi se il tuo utente è attualmente al centro del tavolo e ne ripristini il contenuto. Inoltre stai facendo potenzialmente il lavoro UIImageJPEGRepresentation() molte volte, sarebbe utile per le tue prestazioni di scorrimento se hai fatto questo lavoro una volta in imageLoaderDidFinishDownloading: e poi lo hai memorizzato nella cache.

Poiché sembra che la richiamata avvenga su un thread in background, assicurati di manipolare solo lo UICollectionView dal thread principale.

Problemi correlati