在使用UITableView时,由于cell的重用机制,在获取后台数据并填充cell时,会发生cell重复出现,界面紊乱。但这仅仅在拥有多个section的情况下会出现,没有滚动的时候,单个section的row显示的都是正确的。
以下是示例代码:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath //这个方法是UITableView 的 DataSource方法,作用是用来加载/重用cell的。 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier"; // UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier]; UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; if (cell == nil) { // ... your code cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: SimpleTableIdentifier]; } return cell; }
这里面的变量其实每创建一次tableViewController都会出现:
1. SimpleTableIdentifier:cell的标识, dequeueReusableCellWithIdentifier方法会用到。在alloc cell的时候会传入SimpleTableIdentifier并赋给cell的reuseIdentifier属性
。如果使用dequeueReusableCellWithIdentifier来获取cell,就要确保每个indexPath.row所指向的cell的SimpleTableIdentifier唯一。
2. dequeueReusableCellWithIdentifier::这个方法会返回reuseIdentifier与当前SimpleTableIdentifier相同的cell,这也就是造成顺序混乱的原因,如果没有找到,返回nil。
3. cellForRowAtIndexPath::这个方法会返回与当前indexPath相同的cell,所以就算是所有cell的SimpleTableIdentifier都相同,也会得到正确顺序,如果没有找到,返回nil。
总结:
如果在你的程序中,出现排序混乱或cell内容相同的情况,请核对使用的是dequeueReusableCellWithIdentifier方法还是cellForRowAtIndexPath方法。
由于cellForRowAtIndexPath方法不会出现这种情况,所以如果使用的是dequeueReusableCellWithIdentifier方法,请确保每个cell的reuseIdentifier唯一。
但是cell重用的机制也不能忽略,UITableViewCell有一个队列用来专门存放那些生成过的,但是后来由于滚动tableView而隐藏起来的cell,
比如一个table有20个cell,但是屏幕只能显示5个,(当然iPhone5可能会显示6个),那么就会有其他的cell没有显示出来,但是在滑动tableview的时候便会显现。
而代码中:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
就是从队列中根据标示符取出一个暂时不用的cell,只有cell为nil,也就是队列中没有旧的cell的时候,才会执行:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: SimpleTableIdentifier];
以此生成一个新的cell。
如果有旧的,就不用执行这个语句了,这样节省资源,算作一种重用。
在tableView初始化的时候队列中肯定没有cell的,所以每个cell生成的时候都会执行一遍这个代码:
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier: SimpleTableIdentifier];
当屏幕显示满了,向上滚动显示下一行时,就会把第一行隐藏,放到那个队列中,然后新增加的一行执行语句:
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier: SimpleTableIdentifier];
这时候结果就不是nil了,然后,就跳过语句2了,这样就节约资源了。