首页 > 关于cell重用的一些很纠结的问题(来大神解释下)

关于cell重用的一些很纠结的问题(来大神解释下)


static NSString *orderCellID = @"MyOrderCell";

[self.mTableView registerClass:[MyOrderCell class] forCellReuseIdentifier:orderCellID];
1.MyOrderCell *cell = (MyOrderCell *)[tableView dequeueReusableCellWithIdentifier:orderCellID];

    if (cell == nil) {

       cell = [[MyOrderCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:orderCellID];

    }
2.MyOrderCell *cell = [self.mTableView dequeueReusableCellWithIdentifier:orderCellID forIndexPath:indexPath];

这两种重用cell的方法问题就是...

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

    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
    
    NSLog(@"cell height %f",cell.frame.size.height);
    
    return cell.frame.size.height;
}

如果用方法2.的话为什么
UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
就报错了?????

但是用方法1的话确实是可行的...可以来个大神详细解释下吗


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

    UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
    
    NSLog(@"cell height %f",cell.frame.size.height);
    
    return cell.frame.size.height;
}

这段代码通常不能这么写吧。返回高度不能这样取cell,然后返回高度。要知道这个代理方法在被调用的时候,- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath还没执行,两者的调用顺序一定要明白。
Tableview是预先要拿到高度,然后用重用cell的方式返回cell,cell按照之前的高度进行布局。

所以返回高度的代理方法,一般大概有两种思路:

  1. 拿到cell内部各种UI元素的高度、间距,进行累加计算,见下面参考链接。

  2. 如果采用Autolayout约束,采用`[cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]的方式计算高度,这方面可以参考下
    开源项目https://github.com/forkingdog/UITableView-FDTemplateLayoutCell

可以看下:动态计算UITableViewCell高度详解


第二种 你要先在tableView 注册一下cell


楼上说得对。系统的代理方法最好不要自己主动调用,保不齐会出什么问题。
另外,楼主的问题 2.MyOrderCell *cell = [self.mTableView dequeueReusableCellWithIdentifier:orderCellID forIndexPath:indexPath]; 这样写为什么不行。

官方文档对dequeueReusableCellWithIdentifier:的解释:
Returns a reusable table-view cell object located by its identifier.
A string identifying the cell object to be reused. This parameter must not be nil.

Returns A UITableViewCell object with the associated identifier or nil if no such object exists in the reusable-cell queue.

看见了没,你要想已经有一个reusable的cell,首先你得曾经创建过一个啊!你都没有创建过,系统是不会帮你变出来一个存着的。第一种方法是对的,就是因为当系统发现并没有可重用的cell的时候返回了nil,然后你自己alloc了一个出来,这个cell会被系统加入到一个队列中,下一次你要根据identifier重用的时候系统就有东西拿给你了
查到一个可供参考:链接描述


1 就算可行,返回的也应该是 nil 吧


你的两种方法其实就是一种,是说,

[self.mTableView dequeueReusableCellWithIdentifier:orderCellID forIndexPath:indexPath];

这个方法,不论现在是否有已经生成的等待重用的cell,它都保证会返回一个cell(如果有的话就取,没有的话就再生成一个新的)。但是这个方法调用的时候有一个条件,就是你必须已经调用了registerClass或者registerNib方法注册过,这个文档里面都是写的有的。
而另一个方法则是判断是否有已经生成的等待重用的cell,有的话就取一个返回,没有的话就返回nil,所以需要你在下面判断是否为nil然后自己创建。

[self tableView:tableView cellForRowAtIndexPath:indexPath];

这个方法不能自己手动调用,这个方法返回的cell是要展示在界面上并且参与重用的,如果你手动调用了这个方法,它返回的cell在你算高之后就没用被释放掉了。你代码里面这里算高的时候每次调用方法都会生成一个cell。

所以你所纠结的重用的问题其实就是因为你手动调用了tableView:cellForRowAtIndexPath:这个函数。

【热门文章】
【热门文章】