From cfbcf1d1c2251a7e408e84bd0e3dade6f928ba1d Mon Sep 17 00:00:00 2001 From: William Green Date: Thu, 4 Feb 2016 13:35:30 -0800 Subject: [PATCH 1/2] Update path of demo images in .gitignore --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index ac781e5..c67c252 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,5 @@ profile DerivedData # Demo Images -FastImageCacheDemo/Demo Images/*.jpg +FastImageCache/FastImageCacheDemo/Demo Images/*.jpg Carthage From 16b7ecfe5deb23e34363e15e34e2e48d7bf022a7 Mon Sep 17 00:00:00 2001 From: William Green Date: Thu, 4 Feb 2016 16:27:00 -0800 Subject: [PATCH 2/2] Keeps image views in view hierarchy Create the image views once per cell, and keep them in the content view even if there is no image to show (like in the last row of the table). This gains ~5 FPS on iPad 3 by avoiding expensive calls to -addSubview: and -removeFromSuperview. --- .../Classes/FICDPhotosTableViewCell.m | 68 +++++++++---------- .../Classes/FICDViewController.m | 11 ++- 2 files changed, 36 insertions(+), 43 deletions(-) diff --git a/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m b/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m index eaa24c3..5c7c29d 100644 --- a/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m @@ -19,7 +19,7 @@ @interface FICDPhotosTableViewCell () { NSArray *_photos; NSString *_imageFormatName; - NSMutableArray *_imageViews; + NSArray *_imageViews; UITapGestureRecognizer *_tapGestureRecognizer; } @@ -39,42 +39,28 @@ @implementation FICDPhotosTableViewCell - (void)setPhotos:(NSArray *)photos { if (photos != _photos) { _photos = [photos copy]; - - // Either create the image views for this cell or clear them out if they already exist - if (_imageViews == nil) { - NSInteger photosPerRow = [[self class] photosPerRow]; - _imageViews = [[NSMutableArray alloc] initWithCapacity:photosPerRow]; - - for (NSInteger i = 0; i < photosPerRow; i++) { - UIImageView *imageView = [[UIImageView alloc] init]; - [imageView setContentMode:UIViewContentModeScaleAspectFill]; - [_imageViews addObject:imageView]; - } - } else { - for (UIImageView *imageView in _imageViews) { - [imageView setImage:nil]; - [imageView removeFromSuperview]; - } - } - - NSInteger photosCount = [_photos count]; - for (NSInteger i = 0; i < photosCount; i++) { - FICDPhoto *photo = [_photos objectAtIndex:i]; + + for (NSInteger i = 0; i < [_imageViews count]; i++) { UIImageView *imageView = [_imageViews objectAtIndex:i]; - - if (_usesImageTable) { - [[FICImageCache sharedImageCache] retrieveImageForEntity:photo withFormatName:_imageFormatName completionBlock:^(id entity, NSString *formatName, UIImage *image) { - // This completion block may be called much later. We should check to make sure this cell hasn't been reused for different photos before displaying the image that has loaded. - if (photos == [self photos]) { - [imageView setImage:image]; - } - }]; + + if (i < [_photos count]) { + FICDPhoto *photo = [_photos objectAtIndex:i]; + + if (_usesImageTable) { + [[FICImageCache sharedImageCache] retrieveImageForEntity:photo withFormatName:_imageFormatName completionBlock:^(id entity, NSString *formatName, UIImage *image) { + // This completion block may be called much later. We should check to make sure this cell hasn't been reused for different photos before displaying the image that has loaded. + if (photos == [self photos]) { + [imageView setImage:image]; + } + }]; + } else { + [imageView setImage:[photo thumbnailImage]]; + } } else { - [imageView setImage:[photo thumbnailImage]]; + // Last row might not be full + [imageView setImage:nil]; } } - - [self setNeedsLayout]; } } @@ -117,6 +103,18 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus if (self != nil) { _tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_tapGestureRecognizerStateDidChange)]; [self addGestureRecognizer:_tapGestureRecognizer]; + + NSInteger photosPerRow = [[self class] photosPerRow]; + NSMutableArray *imageViews = [[NSMutableArray alloc] initWithCapacity:photosPerRow]; + + for (NSInteger i = 0; i < photosPerRow; i++) { + UIImageView *imageView = [[UIImageView alloc] init]; + [imageView setContentMode:UIViewContentModeScaleAspectFill]; + [imageViews addObject:imageView]; + [self.contentView addSubview:imageView]; + } + + _imageViews = [imageViews copy]; } return self; @@ -139,14 +137,12 @@ - (void)layoutSubviews { CGFloat outerPadding = [[self class] outerPadding]; CGRect imageViewFrame = CGRectMake(outerPadding, outerPadding, FICDPhotoSquareImageSize.width, FICDPhotoSquareImageSize.height); - - UIView *contentView = [self contentView]; + NSInteger count = [_photos count]; for (NSInteger i = 0; i < count; i++) { UIImageView *imageView = [_imageViews objectAtIndex:i]; [imageView setFrame:imageViewFrame]; - [contentView addSubview:imageView]; imageViewFrame.origin.x += imageViewFrame.size.width + innerPadding; } diff --git a/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m b/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m index f830e87..c81c8bd 100644 --- a/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m +++ b/FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m @@ -95,6 +95,7 @@ - (void)loadView { [_tableView setDelegate:self]; [_tableView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; [_tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone]; + [_tableView registerClass:[FICDPhotosTableViewCell class] forCellReuseIdentifier:[FICDPhotosTableViewCell reuseIdentifier]]; CGFloat tableViewCellOuterPadding = [FICDPhotosTableViewCell outerPadding]; [_tableView setContentInset:UIEdgeInsetsMake(0, 0, tableViewCellOuterPadding, 0)]; @@ -461,13 +462,9 @@ - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger) - (UITableViewCell*)tableView:(UITableView*)table cellForRowAtIndexPath:(NSIndexPath*)indexPath { NSString *reuseIdentifier = [FICDPhotosTableViewCell reuseIdentifier]; - FICDPhotosTableViewCell *tableViewCell = (FICDPhotosTableViewCell *)[table dequeueReusableCellWithIdentifier:reuseIdentifier]; - if (tableViewCell == nil) { - tableViewCell = [[FICDPhotosTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; - [tableViewCell setBackgroundColor:[table backgroundColor]]; - [tableViewCell setSelectionStyle:UITableViewCellSelectionStyleNone]; - } - + FICDPhotosTableViewCell *tableViewCell = (FICDPhotosTableViewCell *)[table dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath]; + tableViewCell.selectionStyle = UITableViewCellSeparatorStyleNone; + [tableViewCell setDelegate:self]; [tableViewCell setImageFormatName:_imageFormatName];