UIColletionView效能調研結果

宋奕發表於2019-03-16

UIColletionView效能調研結果

在之前的code review會議中,遺留了兩個問題:

一、

  1. 複用cell,cell中巢狀子view

  2. 全部使用複用cell

    哪種效能更好?

  1. cell中的子View,使用addSubView和removeFormSuperView來控制子View顯示與隱藏

  2. cell中的子View,一次性addSubView,然後使用hidden屬性,來控制子view顯示與隱藏

    哪種效能更好?

上述是使用文字表述可能理解起來略加困難,我們具體可以參考以下程式碼。並附上相應程式碼的視訊,可以直觀的看出效能的變化情況

一、

  1. 複用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

  1. 全部使用複用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的效能要差一些。

  1. 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

  1. 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的顯示。此種做法,對於效能的要求最小

相關文章