UIColletionView性能调研结果
UIColletionView性能调研结果
在之前的code review会议中,遗留了两个问题:
一、
-
复用cell,cell中嵌套子view
-
全部使用复用cell
哪种性能更好?
二、
-
cell中的子View,使用addSubView和removeFormSuperView来控制子View显示与隐藏
-
cell中的子View,一次性addSubView,然后使用hidden属性,来控制子view显示与隐藏
哪种性能更好?
上述是使用文字表述可能理解起来略加困难,我们具体可以参考以下代码。并附上相应代码的视频,可以直观的看出性能的变化情况
一、
-
复用cell,cell中嵌套子view
每个UICollectoinViewCell中包含10个子view。
UICollectoinView 总共返回5000个cell。每个cell的长宽为屏幕的1/3。总共15000个view
代码表述如下:
@implementation ReuseAllView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setUpView];
}
return self;
}
- (void)setUpView {
NSInteger i = 0;
CGFloat margin = 10;
NSInteger count_row = 10;
CGFloat v_w = (CGRectGetWidth(self.frame) - (count_row - 1)*margin)/count_row;
for (; i<count_row; i++) {
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(i*(margin+v_w), 0, v_w, CGRectGetHeight(self.frame))];
view.backgroundColor = [UIColor blueColor];
[self.contentView addSubview:view];
}
}
@end
#import "ViewController.h"
#import "reuseview/ReuseViewCell.h"
#import "reuseview/ReuserCellCell.h"
#import "reuseview/ReuseAllCell.h"
#import "reuseview/ReuseAllView.h"
#define UseCell ReuseAllCell
@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>
@property (nonatomic, strong)UICollectionView *colletionView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.colletionView];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 5000;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([UseCell class]) forIndexPath:indexPath];
if ([cell respondsToSelector:@selector(updateView)]) {
[cell performSelector:@selector(updateView)];
}
return cell;
}
- (UICollectionView *)colletionView {
if (!_colletionView) {
UICollectionViewFlowLayout *flowlayout = [[UICollectionViewFlowLayout alloc]init];
flowlayout.scrollDirection = UICollectionViewScrollDirectionVertical;
flowlayout.minimumLineSpacing = 0.;
flowlayout.minimumInteritemSpacing = 0.;
flowlayout.estimatedItemSize = CGSizeZero;
flowlayout.itemSize = CGSizeMake(self.view.frame.size.width/3, self.view.frame.size.width/3);
_colletionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:flowlayout];
_colletionView.backgroundColor = [UIColor whiteColor];
[_colletionView registerClass:[UseCell class] forCellWithReuseIdentifier:NSStringFromClass([UseCell class])];
_colletionView.delegate = self;
_colletionView.dataSource = self;
}
return _colletionView;
}
@end
滑动到最底部,再滑动到最顶部,性能反馈如下:
image-
全部使用复用cell。
UIColloctionView返回总共15000个cell。每个cell宽屏幕的1/30。长屏幕的1/3。
代码表述如下:
#import "ReuseAllCell.h"
@implementation ReuseAllCell
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor orangeColor];
}
return self;
}
@end
#import "ViewController.h"
#import "reuseview/ReuseViewCell.h"
#import "reuseview/ReuserCellCell.h"
#import "reuseview/ReuseAllCell.h"
#import "reuseview/ReuseAllView.h"
#define UseCell ReuseAllCell
@interface ViewController ()<UICollectionViewDelegate,UICollectionViewDataSource>
@property (nonatomic, strong)UICollectionView *colletionView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self.view addSubview:self.colletionView];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 5000*3;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UseCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:NSStringFromClass([UseCell class]) forIndexPath:indexPath];
if ([cell respondsToSelector:@selector(updateView)]) {
[cell performSelector:@selector(updateView)];
}
return cell;
}
- (UICollectionView *)colletionView {
if (!_colletionView) {
UICollectionViewFlowLayout *flowlayout = [[UICollectionViewFlowLayout alloc]init];
flowlayout.scrollDirection = UICollectionViewScrollDirectionVertical;
flowlayout.minimumLineSpacing = 0.;
flowlayout.minimumInteritemSpacing = 0.;
flowlayout.estimatedItemSize = CGSizeZero;
flowlayout.itemSize = CGSizeMake(self.view.frame.size.width/30, self.view.frame.size.width/3);
_colletionView = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:flowlayout];
_colletionView.backgroundColor = [UIColor whiteColor];
[_colletionView registerClass:[UseCell class] forCellWithReuseIdentifier:NSStringFromClass([UseCell class])];
_colletionView.delegate = self;
_colletionView.dataSource = self;
}
return _colletionView;
}
@end
滑动到最底部,再滑动到最顶部,性能反馈如下:
image可以从视频上看出:无论从CPU峰值还是,RAM的占用情况,全部复用cell的性能都比复用cell再嵌套view的性能要差一些。
二、
-
cell中的子View,使用addSubView和removeFormSuperView来控制子View显示与隐藏
UICollectionView总共返回5000个cell。
其中每个cell中嵌套500个view。
代码表述如下:
#import "ReuseViewCell.h"
@interface ReuseViewCell ()
@property (nonatomic, strong)NSMutableArray *views;
@end
@implementation ReuseViewCell
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.views = [NSMutableArray array];
[self setUpView];
}
return self;
}
- (void)setUpView {
if (self.views.count) {
[self updateView];
} else {
for (NSInteger i = 0; i<500; i++) {
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame))];
view.backgroundColor = [UIColor redColor];
[self.contentView addSubview:view];
[self.views addObject:view];
}
}
}
- (void)updateView {
[self.views makeObjectsPerformSelector:@selector(removeFromSuperview)];
for (UIView *view in self.views) {
[self.contentView addSubview:view];
}
}
@end
滑动到最底部,再滑动到最顶部,性能反馈如下:
image- cell中的子View,一次性addSubView,然后使用hidden属性,来控制子view显示与隐藏。
UICollectionView返回5000个cell,每个cell中嵌套500个view。
代码表述如下:
#import "ReuserCellCell.h"
@interface ReuserCellCell ()
@end
@implementation ReuserCellCell
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setUpView];
}
return self;
}
- (void)setUpView {
if (self.contentView.subviews.count) {
[self updateView];
} else {
for (NSInteger i = 0; i<500; i++) {
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame))];
view.backgroundColor = [UIColor greenColor];
[self.contentView addSubview:view];
}
}
}
- (void)updateView {
[self.contentView.subviews makeObjectsPerformSelector:@selector(setHidden:) withObject:@(YES)];
[self.contentView.subviews makeObjectsPerformSelector:@selector(setHidden:) withObject:@(NO)];
}
@end
滑动到最底部,再滑动到最顶部,性能反馈如下:
image从上述结果,可以很明显的看出,第一种方式比第二种方式,无论从cup使用率还是RAM的占用情况,都差了很多,并且,第一种方式,明显造成了页面卡顿。
于此同时,在代码中,第一种方式的写法也会造成不必要的内存占用
综上所述,后续我们在使用复用机制的时候,例如日历,可以复用大cell然后嵌套子View去实现,并且,一定要一次性addSubView后再单独控制子view的显示。此种做法,对于性能的要求最小