Skip to content

Commit 16b7ecf

Browse files
author
William Green
committed
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.
1 parent cfbcf1d commit 16b7ecf

File tree

2 files changed

+36
-43
lines changed

2 files changed

+36
-43
lines changed

FastImageCache/FastImageCacheDemo/Classes/FICDPhotosTableViewCell.m

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ @interface FICDPhotosTableViewCell () <UIGestureRecognizerDelegate> {
1919
NSArray *_photos;
2020
NSString *_imageFormatName;
2121

22-
NSMutableArray *_imageViews;
22+
NSArray *_imageViews;
2323
UITapGestureRecognizer *_tapGestureRecognizer;
2424
}
2525

@@ -39,42 +39,28 @@ @implementation FICDPhotosTableViewCell
3939
- (void)setPhotos:(NSArray *)photos {
4040
if (photos != _photos) {
4141
_photos = [photos copy];
42-
43-
// Either create the image views for this cell or clear them out if they already exist
44-
if (_imageViews == nil) {
45-
NSInteger photosPerRow = [[self class] photosPerRow];
46-
_imageViews = [[NSMutableArray alloc] initWithCapacity:photosPerRow];
47-
48-
for (NSInteger i = 0; i < photosPerRow; i++) {
49-
UIImageView *imageView = [[UIImageView alloc] init];
50-
[imageView setContentMode:UIViewContentModeScaleAspectFill];
51-
[_imageViews addObject:imageView];
52-
}
53-
} else {
54-
for (UIImageView *imageView in _imageViews) {
55-
[imageView setImage:nil];
56-
[imageView removeFromSuperview];
57-
}
58-
}
59-
60-
NSInteger photosCount = [_photos count];
61-
for (NSInteger i = 0; i < photosCount; i++) {
62-
FICDPhoto *photo = [_photos objectAtIndex:i];
42+
43+
for (NSInteger i = 0; i < [_imageViews count]; i++) {
6344
UIImageView *imageView = [_imageViews objectAtIndex:i];
64-
65-
if (_usesImageTable) {
66-
[[FICImageCache sharedImageCache] retrieveImageForEntity:photo withFormatName:_imageFormatName completionBlock:^(id<FICEntity> entity, NSString *formatName, UIImage *image) {
67-
// 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.
68-
if (photos == [self photos]) {
69-
[imageView setImage:image];
70-
}
71-
}];
45+
46+
if (i < [_photos count]) {
47+
FICDPhoto *photo = [_photos objectAtIndex:i];
48+
49+
if (_usesImageTable) {
50+
[[FICImageCache sharedImageCache] retrieveImageForEntity:photo withFormatName:_imageFormatName completionBlock:^(id<FICEntity> entity, NSString *formatName, UIImage *image) {
51+
// 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.
52+
if (photos == [self photos]) {
53+
[imageView setImage:image];
54+
}
55+
}];
56+
} else {
57+
[imageView setImage:[photo thumbnailImage]];
58+
}
7259
} else {
73-
[imageView setImage:[photo thumbnailImage]];
60+
// Last row might not be full
61+
[imageView setImage:nil];
7462
}
7563
}
76-
77-
[self setNeedsLayout];
7864
}
7965
}
8066

@@ -117,6 +103,18 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus
117103
if (self != nil) {
118104
_tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_tapGestureRecognizerStateDidChange)];
119105
[self addGestureRecognizer:_tapGestureRecognizer];
106+
107+
NSInteger photosPerRow = [[self class] photosPerRow];
108+
NSMutableArray *imageViews = [[NSMutableArray alloc] initWithCapacity:photosPerRow];
109+
110+
for (NSInteger i = 0; i < photosPerRow; i++) {
111+
UIImageView *imageView = [[UIImageView alloc] init];
112+
[imageView setContentMode:UIViewContentModeScaleAspectFill];
113+
[imageViews addObject:imageView];
114+
[self.contentView addSubview:imageView];
115+
}
116+
117+
_imageViews = [imageViews copy];
120118
}
121119

122120
return self;
@@ -139,14 +137,12 @@ - (void)layoutSubviews {
139137
CGFloat outerPadding = [[self class] outerPadding];
140138

141139
CGRect imageViewFrame = CGRectMake(outerPadding, outerPadding, FICDPhotoSquareImageSize.width, FICDPhotoSquareImageSize.height);
142-
143-
UIView *contentView = [self contentView];
140+
144141
NSInteger count = [_photos count];
145142

146143
for (NSInteger i = 0; i < count; i++) {
147144
UIImageView *imageView = [_imageViews objectAtIndex:i];
148145
[imageView setFrame:imageViewFrame];
149-
[contentView addSubview:imageView];
150146

151147
imageViewFrame.origin.x += imageViewFrame.size.width + innerPadding;
152148
}

FastImageCache/FastImageCacheDemo/Classes/FICDViewController.m

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ - (void)loadView {
9595
[_tableView setDelegate:self];
9696
[_tableView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
9797
[_tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
98+
[_tableView registerClass:[FICDPhotosTableViewCell class] forCellReuseIdentifier:[FICDPhotosTableViewCell reuseIdentifier]];
9899

99100
CGFloat tableViewCellOuterPadding = [FICDPhotosTableViewCell outerPadding];
100101
[_tableView setContentInset:UIEdgeInsetsMake(0, 0, tableViewCellOuterPadding, 0)];
@@ -461,13 +462,9 @@ - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)
461462
- (UITableViewCell*)tableView:(UITableView*)table cellForRowAtIndexPath:(NSIndexPath*)indexPath {
462463
NSString *reuseIdentifier = [FICDPhotosTableViewCell reuseIdentifier];
463464

464-
FICDPhotosTableViewCell *tableViewCell = (FICDPhotosTableViewCell *)[table dequeueReusableCellWithIdentifier:reuseIdentifier];
465-
if (tableViewCell == nil) {
466-
tableViewCell = [[FICDPhotosTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier];
467-
[tableViewCell setBackgroundColor:[table backgroundColor]];
468-
[tableViewCell setSelectionStyle:UITableViewCellSelectionStyleNone];
469-
}
470-
465+
FICDPhotosTableViewCell *tableViewCell = (FICDPhotosTableViewCell *)[table dequeueReusableCellWithIdentifier:reuseIdentifier forIndexPath:indexPath];
466+
tableViewCell.selectionStyle = UITableViewCellSeparatorStyleNone;
467+
471468
[tableViewCell setDelegate:self];
472469
[tableViewCell setImageFormatName:_imageFormatName];
473470

0 commit comments

Comments
 (0)