2013-09-03 4 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 잘못 원칙을 unsterstanding 무엇입니까?

미리 감사드립니다. 친절한 답변, Jan

+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: 번 수행 한 다음 캐시하면 스크롤 성능에 도움이됩니다.

배경 스레드에서 콜백이 발생하는 것처럼 보이기 때문에 메인 스레드에서 UICollectionView 만 조작해야합니다.

관련 문제