美文网首页
iOS-tableViewCell的重用机制

iOS-tableViewCell的重用机制

作者: MT_suny | 来源:发表于2019-05-05 19:16 被阅读0次

    从14年接触iOS已经一晃过去快五个年头了,很少在简书上记录自己学习的点滴.现如今刚好有个契机,觉得写一些自己忘记的东西帮助自己回忆.也希望对刚学习的小伙伴有所帮助.

    首先来了解一下什么是tableViewCell的重用机制,如图:


    3934130-9acf3a9fc141cf51.png

    图片展示的虚线部分我们假设是手机屏幕展示tableView的区域.那么现在我们的系统做了什么呢?首先系统会创建一个绑定重用标识符的重用池.在重用池中有着这样两个队列集合,分别存放着正在使用的cell和等待使用的cell,A1已经滑动到屏幕区域外,这时候系统会把相应的cell从使用队列中删除这个cell,放到等待使用的队列中去.以便于下一次使用,这样循环往复的操作就实现了tableViewCell的重用.

    那么,既然我们知道了重用机制我们要怎么手动实现类似系统的重用机制呢.话不多说上代码:

    首先我们创建一个ReusePool来模拟系统的重用池:

    #import "ViewReusePool.h"
    
    @interface ViewReusePool ()
    //等待使用的队列
    @property (nonatomic, strong) NSMutableSet *waitUseQueue;
    //使用中的队列
    @property (nonatomic, strong) NSMutableSet *usingQueue;
    
    @end
    
    @implementation ViewReusePool
    
    - (instancetype)init
    {
        self = [super init];
        if (self) {
            _waitUseQueue = [NSMutableSet set];
            _usingQueue = [NSMutableSet set];
        }
        return self;
    }
    
    - (UIView *)dequeueReuseableView {
        //从重用队列取出一个可重用的view
        UIView *view = [_waitUseQueue anyObject];
        if (view == nil) {
            return nil;
        }
        else{
            //进行队列移动
            [_waitUseQueue removeObject:view];
            [_usingQueue addObject:view];
            return view;
        }
    }
    
    - (void)addUsingView:(UIView *)view{
        if (view == nil) {
            return;
        }
        //添加视图到使用的队列中
        [_usingQueue addObject:view];
    }
    
    - (void)reset {
        UIView *view = nil;
        while ((view = [_usingQueue anyObject])) {
            //从使用的队列中移除
            [_usingQueue removeObject:view];
            //加入到等待使用的队列中
            [_waitUseQueue addObject:view];
        }
    }
    
    @end
    

    这就是一个简单的重用池实现代码.

    我现在要测试重用池是否起作用,我们实现一个字母索引的tableView来测试结果:

    #import "IndexedTableView.h"
    #import "ViewReusePool.h"
    
    @interface IndexedTableView (){
        //定义一个容器view
        UIView *containerView;
        //定义一个重用池
        ViewReusePool *reusePool;
    }
    
    @end
    
    @implementation IndexedTableView
    
    - (void)reloadData {
        [super reloadData];
        //懒加载
        if (containerView == nil) {
            containerView = [[UIView alloc] initWithFrame:CGRectZero];
            containerView.backgroundColor = [UIColor whiteColor];
            //避免索引条随着table滚动
            [self.superview insertSubview:containerView aboveSubview:self];
        }
        if (reusePool == nil) {
            reusePool = [[ViewReusePool alloc] init];
        }
        //标记所有视图为可重用状态
        [reusePool reset];
        //reload字母索引条
        [self reloadIndexedBar];
    }
    
    - (void)reloadIndexedBar {
        //获取字母索引条的显示内容
        NSArray <NSString *> *arrayTitles = nil;
        if ([self.indexDataSource respondsToSelector:@selector(indexTitlesForIndexTableView:)]) {
            arrayTitles = [self.indexDataSource indexTitlesForIndexTableView:self];
        }
        //判断字母索引是否为空
        if (!arrayTitles || arrayTitles.count <= 0) {
            [containerView setHidden:YES];
            return;
        }
        NSUInteger count = arrayTitles.count;
        CGFloat buttonWidth = 60;
        CGFloat buttonHeight = self.frame.size.height / count;
        for (int i = 0; i < [arrayTitles count]; i++) {
            NSString *title = [arrayTitles objectAtIndex:i];
            //从重用池中取出一个Button出来
            UIButton *button = (UIButton *)[reusePool dequeueReuseableView];
            if (button == nil) {
                button = [[UIButton alloc] initWithFrame:CGRectZero];
                button.backgroundColor = [UIColor whiteColor];
                //注册button到重用池当中
                [reusePool addUsingView:button];
                NSLog(@"新创建一个Button");
            }else{
                NSLog(@"Button 重用了");
            }
            //添加button到父视图中
            [containerView addSubview:button];
            [button setTitle:title forState:UIControlStateNormal];
            [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
            [button setFrame:CGRectMake(0, i * buttonHeight, buttonWidth, buttonHeight)];
        }
        [containerView setHidden:NO];
        containerView.frame = CGRectMake(self.frame.origin.x + self.frame.size.width - buttonWidth, self.frame.origin.y, self.frame.size.width,self.frame.size.height);
    }
    
    
    @end
    

    这是一个的自定义tableView用来实现字母索引条.

    有了展示字母索引条的tableView,我们在ViewController中写我们的实现代码:

    #import "ViewController.h"
    #import "IndexedTableView.h"
    @interface ViewController ()<UITableViewDelegate,UITableViewDataSource,IndexedTableViewDataSource>
    {
        IndexedTableView *tableView;//带索引条的tableView
        UIButton *button;
        NSMutableArray *dataSource;
    }
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //创建一个tableView
        tableView = [[IndexedTableView alloc] initWithFrame:CGRectMake(0, 60, self.view.frame.size.width, self.view.frame.size.height - 60) style:UITableViewStylePlain];
        tableView.dataSource = self;
        tableView.delegate = self;
        //设置索引数据源
        tableView.indexDataSource = self;
        [self.view addSubview:tableView];
        //创建一个按钮
        button = [[UIButton alloc] initWithFrame:CGRectMake(0, 20, self.view.frame.size.width, 40)];
        button.backgroundColor = [UIColor redColor];
        [button addTarget:self action:@selector(doAction:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
        //数据源
        dataSource = [NSMutableArray array];
        for (int i = 0; i < 100; i++) {
            [dataSource addObject:@(i + 1)];
        }
    }
    
    - (void)doAction:(UIButton *)snder {
        NSLog(@"reloadData");
        [tableView reloadData];
    }
    
    #pragma indexTitlesForIndexDataSource
    - (NSArray<NSString *> *)indexTitlesForIndexTableView:(UITableView *)tableView{
        //奇数次调用返回6个字母,偶数次调用返回11个
        static BOOL change = NO;
        if (change) {
            change = NO;
            return @[@"A",@"B",@"C",@"D",@"E",@"F",@"G",@"H",@"I",@"J",@"K"];
        }else{
            change = YES;
            return @[@"A",@"B",@"C",@"D",@"E",@"F"];
        }
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        return [dataSource count];
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass([UITableViewCell class])];
        if (!cell) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:NSStringFromClass([UITableViewCell class])];
        }
        cell.textLabel.text = [[dataSource objectAtIndex:indexPath.row] stringValue];
        return cell;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
        return 40;
    }
    

    我们可以看到通过上面的tableView展示出的界面如下:


    3934130-67b78a40920a08ed.png

    初始化的时候我们的tableView创建了6个按钮.(这里说明一下字母索引不能滑动.并且平分屏幕高度.所以会创建数组count个button).当我们点击红色按钮的时候如图:


    3934130-abe962d30da70ad5.png

    点击按钮刷新数据时候会调用自定义tableView的DataSource.这里我们通过日志可以看出界面展现了11个按钮但是其中6个按钮是之前创建过的.这里被复用了.整个测试过程相信你对重用机制有了更深刻的了解demo;

    相关文章

      网友评论

          本文标题:iOS-tableViewCell的重用机制

          本文链接:https://www.haomeiwen.com/subject/hwtkoqtx.html