之前面试的时候会有很多人问道 UITableviewCellde 重用机制, 大部分回答都是
在缓存池初中通过 dequeueReusableCellWithIdentifier:CellIdentifier 方法取出可重用的 cell, 在一个 cell 离开屏幕显示的范围内, 会自动被加入到缓存池中,然后在缓存池中取出一个 cell, 放到当前屏幕上;用重用机制会节省性能,避免出现一些因为网络因素而造成的卡顿现象。
复用机制避免了大量的初始化过程, 我们可以节约很大一部分资源; 下面我们来试着模仿 tableview 创建一个复用视图吧~
实例化一个重用池;
新建一个继承自NSObject
的类, reusePool; 在reusePool 中定义三个方法,
在类的.m
文件中, 实现刚才定义的几个方法, 并定义两个属性, wattingQueue
和 usingQueue
, 作为存放视图的容器; 实现刚才定义的几个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| - (instancetype)init { self = [super init]; if (self) { _waitingQueue = [NSMutableSet set]; _useingQueue = [NSMutableSet set]; } return self; } // 如果存在, 从等待队列中移除一个, 在使用中的队列增加一个 -(UIView *)getReuseTableView{ UIView *view = [_waitingQueue anyObject]; if (view == nil) { return nil; }else{ [_waitingQueue removeObject:view]; [_useingQueue addObject:view]; return view; } } //添加可重用视图到重用池 -(void)addViewForReusePool:(UIView *)view{ if (view == nil) { return; } [_useingQueue addObject:view]; } //重置重用池 -(void)reset{ UIView *view = nil; while ((view = [_useingQueue anyObject]) ) { [_useingQueue removeObject:view]; [_waitingQueue addObject:view]; } }
|
实现视图
定义一个继承自UITableView
的视图类, reuseTableView
; 给 reuseTableView
设置一个代理方法, 来获取需要用到的数据;
1 2 3 4 5 6 7 8 9 10 11 12
| #import <UIKit/UIKit.h> @protocol QKReuseTableViewDataSource <NSObject> /** 获取字母索引条 @param tableview tableview @return 结果数组 */ -(NSArray <NSString*> *)indexTitleFromReuseTable:(UITableView *)tableview; @end @interface QKReuseTableView : UITableView @property (nonatomic,weak) id <QKReuseTableViewDataSource> indexDataSource; @end
|
在. m
文件中定义两个属性
1 2 3 4 5 6
| @interface QKReuseTableView () { UIView *containerView; QKReusePool *reusePool; } @end
|
重写 tableview
的reloadData
方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| -(void)reloadData{ [super reloadData]; if (containerView == nil) { containerView = [[UIView alloc] init]; containerView.backgroundColor = UIColor.whiteColor; [self.superview insertSubview:containerView aboveSubview:self]; } if (reusePool == nil) { reusePool = [[QKReusePool alloc] init]; } //初始化的时候重置重用池 [reusePool reset]; // reload 索引条 [self reloadIndexTitle]; } -(void)reloadIndexTitle{ // 设置一个title数组 NSArray <NSString *> * titleArray = nil; if ([self.indexDataSource respondsToSelector:@selector(indexTitleFromReuseTable:)]) { titleArray = [self.indexDataSource indexTitleFromReuseTable:self]; } if (!titleArray titleArray.count<=0) { [containerView setHidden:YES]; return; } NSUInteger count = titleArray.count; CGFloat btnWidth = 60; CGFloat btnHeight = self.frame.size.height/count; for (int i = 0; i< count; i++) { NSString *title = [titleArray objectAtIndex:i]; UIButton *btn = (UIButton *)[reusePool getReuseTableView]; if (btn == nil) { btn = [[UIButton alloc] initWithFrame:CGRectZero]; btn.backgroundColor = UIColor.whiteColor; [reusePool addViewForReusePool:btn]; NSLog(@"creat a btn"); }else{ NSLog(@"reuse button"); } [containerView addSubview:btn]; [btn setTitle:title forState:UIControlStateNormal]; [btn setTitleColor:UIColor.blackColor forState:UIControlStateNormal]; [btn setFrame:CGRectMake(0, i*btnHeight, btnWidth, btnHeight)]; } [containerView setHidden:NO]; containerView.frame = CGRectMake(self.frame.origin.x + self.frame.size.width - btnWidth, self.frame.origin.y, btnWidth, self.frame.size.height); }
|
代码在reuseCell 文件夹 git仓库链接地址