zoukankan      html  css  js  c++  java
  • cell的复用机制

    以下全部都是转载自别人的博客:http://blog.sina.com.cn/s/blog_9c3c519b01016aqu.html

    转自:http://www.2cto.com/kf/201207/144337.html

    今天在看iphone开发秘籍的时候,遇到这个问题,就仔细的深入了一下,通过测试,获取了一些自认为还不错的结论,希望对大家在cell复用方面遇到的一些问题会有所帮助。

    本篇文章只讲原理,对于如果对cell做界面,不深入讲述。鉴于我的表达能力有限,可能会有我自己清楚,但是却说不清楚的地方,如有问题,留言给我。


    UITableView在界面的编程用的甚多,iphone开发也三月有余了,每次用到cellForRowAtIndexPath的委托方法的时候,都是直接copy代码,自己略加一些界面的修改,对于cell的标示符都是static NSString* identifier = @"cell";然后调用dequeueReusableCellWithIdentifier方法获取cell,如果cell为空,再调用[[[UITableViewCellalloc]initWithStyle方法新创建一个,根本没有考虑过更深一些的东西。为了讲解清楚,现放上一段代码,代码copy自iphone开发秘籍,本人为了讲解,略加修改。以下所有讲解均依照此代码进行,因此,如果您希望能够透彻的了解cell的复用机制,建议实际运行以下,跟着讲解,查看效果。代码只有tableVIew的委托方法,因此您需要自己创建工程,把这些委托方法加进去。


    上文一共四个委托方法,表明tableView一个section,有32行,高度为58.关于tableView的高度那个委托方法的返回的高度值,建议最好自己运行程序查看以下,最终达到一页的界面显示8个cell,第8个cell显示一半也行,但是不能显示9和7个cell。我这里之所以为58,由于(480 - 44)/ 58 为7.5 的样子,44为navigationBar的高度,480为屏幕的高度。总之,需要达到的效果是一页显示7个多的cell。还有那个icon.png需要自己准备了,要把它显示出来。是不是很麻烦呀?没办法,谁让我们在获得知识呢,知识总是需要点功夫的。//经鉴定这些都是废话,可忽略不计---SandyZhang 鉴定。


    [cpp] 
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView  
    {  
        return 1;  

     
    - (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section  

        return 32; 

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 

        return 58; 

    - (UITableViewCell *)tableView:(UITableView *)tView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

        UITableViewCellStyle style; 
        NSString *cellType; 
         
        switch (indexPath.row % 4) 
        { 
            case 0: 
                style = UITableViewCellStyleDefault; 
                cellType = @"Default Style"; 
                //有标题没有正文(没有细节文字)。可选的图片 
                break; 
            case 1: 
                style = UITableViewCellStyleSubtitle; 
                cellType = @"Subtitle Style"; 
                //标题和正文方式,上下排布。可选的图片 
                break; 
            case 2: 
                style = UITableViewCellStyleValue1; 
                cellType = @"Value1 Style"; 
                //左边文字左对齐,右边文字右对齐。可选的图片 
                break; 
            case 3: 
                style =  UITableViewCellStyleValue2; 
                cellType =  @"Value2 Style"; 
                //左边文字右对齐,蓝色;右边文字左对齐,黑色。没有图片 
                break; 
                 
        } 
        static int i = 0; 
        UITableViewCell *cell = [tView dequeueReusableCellWithIdentifier:cellType]; 
        if (!cell)  
        { 
            cell = [[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:cellType] autorelease]; 
            ++i; 
            NSLog(@"cell created %d times", i); 
        } 
         
        if (indexPath.row > 3)  
            cell.imageView.image = [UIImage imageNamed:@"icon.png"]; 
         
        cell.textLabel.text = cellType; 
        cell.detailTextLabel.text = @"Subtitle text"; 
        return cell; 

    //前方高能预警,请集中精力----SandyZhang 鉴定。
    首先讲解一下复用队列:

    复用队列的元素增加:只有在cell被滑动出界面的时候,此cell才会被加入到复用队列中。每次在创建cell的时候,程序会首先通过调用dequeueReusableCellWithIdentifier:cellType方法,到复用队列中去寻找标示符为“cellType”的cell,如果找不到,返回nil,然后程序去通过调用[[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:cellType] autorelease]来创建标示符为“cellType”的cell。

    先运行一次程序,不要滑动cell,查看打印日志,会有打印"cell create 1 times",,,"cell create 8 times",一共有8个日志,表明cell创建了8次,这个日志打印是在cellForRowAtIndexPath中的创建cell的时候打印的。然后慢慢向下(向下的意思,实际上是手向上滑动,让界面显示下一个cell,向上与之相反)滑动cell,到显示第九个cell的时候,会看到打印一条日志"cell create 9 times",然后继续慢慢向下滑动,会有"cell create 10 times",直到滑动到第12个cell以后,cell被创建了12个之后,以后再怎么滑动,cell都不会被创建了。也就是说本tableView要完整的工作,一共创建了12个cell。

    开始解释原因了:

    第一页的界面一共需要展示8个cell,故而cell需要创建8次,每一个cell负责自己的数据显示。此8个创建以后,复用队列依然为空(因为你此时还没有滑动cell呢,复用队列的元素不会增加)。然后在向下滑动显示出第9个cell的时候,还会调用cellForRowAtIndexPath方法,在此方法中,它首先到可复用队列中去找,由于此时队列为空,它创建了一个cell,打印日志,同时当第1个cell滑动出界面之外,第一个cell进入到复用队列中,队列中有一个元素,此元素的表示符为@"Default Style"。然后继续向下滑动cell,开始显示第10个cell,它同样到复用队列中去找,第10个cell的标示符为@"Subtitle Style",但是队列中唯一的cell的标示符为@"Default Style",根据标示符寻找,没有找到,故而再次创建一个新的cell,同时将滑动出界面的第2个cell进入复用队列。此时复用队列有两个元素,标示符为@"Default Style",@"Subtitle Style"。同样的道理,滑动到第11个cell的时候,第3个cell入队,第12个cell的时候,第4个cell入队。此时复用队列的元素个数为四个,标示符分别为:@"Default Style",@"Subtitle Style",@"Value1 Style",@"Value2 Style".然后继续滑动cell,当滑动到第13个cell的时候,它的标示符为@"Default Style",它到复用队列中去找,可以找到。故而,这个cell就不会被创建了,同理,再次向下滑动,以下的所有cell都可以根据标示符找到对应的cell,不会有被创建的。在向下滑动的过程中,滑动出去的cell会被入队,不过只入队创建了的cell,也就是说最终队列中会有12个cell。对于每次取对应标示符的元素,到底取的是哪一个?采用的什么策略?这个我不知道,我通过打印查看的是在向下滑动的过程中,一直顺着队列找,队列是一个循环队列。向上滑动的时候,逆着队列向上找,由于是循环队列,一直在转圈。

    如果你仔细看的话,你会发现第一个cell本来没有图片,为什么一划下去再次滑动(如果滑动的距离远,一次搞定,如果滑动的距离近,多上下滑动几次)上来又有图片了呢?这个就要思考一个:第一个cell在滑出界面又划入界面的时候,是从复用队列拿到的。复用队列有12个元素,第1,5,9还第一个cell有相同的标示符,第1个没有图片,第5个和第9个有图片。当用户复用的是第一个cell的时候,它是没有图片,当用户复用第5,9个cell的时候,它是有图片的。因此,当你上下滑动,查看第一个cell的时候,你会看到它一会有图片,一会没有图片。这个跟复用时候的队列查找规则有关。

    //看到事件篇瞬间感觉萌萌哒---SandyZhang 鉴定。
    实用篇:

    说了那么多,全是关于原理的。现在说点实用的。如果你想在所有的cell中添加一个按钮,你是应该在if中添加,还是应该在if之外添加呢?毫无疑问,应该在if中,如果你是在if的外面添加的,那会导致,你在向下滑动cell的过程中,取出来的cell本来已经带有button了,而你还在addSubview,按钮越来越多。或者你可以采用在if外面添加,前提是每次先cell remove掉其所有的子视图。这样太消耗cpu,麻烦了。如果你想一行隔着一行有按钮和没有按钮,你该怎么做呢?稍微思考一下,这个可是两种风格的cell,故而在滑出界面进行重用的时候,它们应该属于不同的标示符。于是你在创建cell的时候,应该去指定两种标示符,创建两种cell。当然,也许你聪明了,我是不是可以在if之外先remove掉cell的所有子视图,然后根据row % 2 == 0或者!=0 来进行addSubView:button吗?答案当然是肯定的,但是这样还是同样的问题,太消耗cpu了。平常我们给每一个cell添加了一个button,肯定要添加事件的。对于不同的button,响应不同的事件?那么我是不是通过在if语句中给button设置它的tag标记(例如button.tag = indexpath.row)来实现呢?哈哈,你应该足够聪明了吧,当然不行。你可以这样想,if语句是用来创建的,它只被执行了(例如上面的例子:12次),但是你可能有几百行的cell,当然你的tag也就只有12个了,明显不对应。像这样的,应该怎么处理呢?答案是:放在if的外面。你在if外面设置了tag标记,当然,在某一个具体的时间点上,仍然只有12个标记,但是这12个标记是可变的,例如当前界面显示第100-111号的cell,那么此时的button的tag就会是100-111了,仍然是12个按钮,但是它们会根据用户的滑动,进行不同的tag切换,相当于拥有了很多个按钮。如果你没有被我说的话给弄晕,脑袋又足够清醒的话,你应该可以得出以下的结论:对于界面的定制,放在if中比较好,一个cell中只创建一次;对于数据的定制,放在if外面比较好,对于不同的cell,表示不同的内容,虽然只有12个cell,但是cell中存放的数据我可以任意的映射。如果你得出了这个结论,那么如果在加上textField,label等等,你应该可以轻松搞定。不仅仅是表面上,更重要的是,你理解了原理,掌握了机制,万变都不怕,即使有新的需求,脑袋想想,或者拿着这篇文章看看,希望能给你一些启示。

  • 相关阅读:
    JavaScript
    94.Binary Tree Inorder Traversal
    144.Binary Tree Preorder Traversal
    106.Construct Binary Tree from Inorder and Postorder Traversal
    105.Construct Binary Tree from Preorder and Inorder Traversal
    90.Subsets II
    78.Subsets
    83.Merge Sorted Array
    80.Remove Duplicates from Sorted Array II
    79.Word Search
  • 原文地址:https://www.cnblogs.com/xujiahui/p/6025638.html
Copyright © 2011-2022 走看看