问题的提出:
有时候我们经常需要自定义tableView的cell,当cell里面的布局较为复杂时往往舍弃纯代码的方式而改用xib的方式进行自定义。当我们用纯代码的方式布局cell时,往往会在cell的initWithStyle: reuseIdentifier: 方法里面用纯代码进行布局,然后在外部VC的cellForRowAtIndexPath方法里面我们会这么写,假定自定义的cell为Cell,继承自UITableViewCell:
static NSString *CellIdentifier = @"Cell"; Cell *cell = (Cell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[[Cell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.titleLabel.text = [self.dataList objectAtIndex:indexPath.row]; return cell;
上述这么写完全没有问题,因为教科书跟各种教程都是这么写的,上述代码对cell进行了重用。但如果我们现在想用xib来布局呢?看到过不少代码是这么写的:
static NSString *CellIdentifier = @"Cell"; Cell *cell = (Cell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { cell = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([Cell class]) owner:self options:nil] objectAtIndex:0]; //cell = [[[Cell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.titleLabel.text = [self.dataList objectAtIndex:indexPath.row];return cell;
唯一区别的地方在于红色的位置:cell的初始化不再通过initWithStyle函数,因为我们现在用xib布局,所有的控件信息都在xib里面,因此我们根据Cell所对应的xib名称来加载xib以创建cell。但是你注意到没,第二种方法的红色部分并没有包含任何重用信息,也就是说,每次拖动tableview,都会一直创建不同的cell,当要显示的cell很多时内存问题就显露出来了。
为了解决这个问题,我们换用另一种更好的方式。
直接放优化后的代码,UINib类可以先不看,不影响代码的理解:
static NSString *CellIdentifier = @"Cell"; BOOL nibsRegistered = NO; if (!nibsRegistered) { UINib *nib = [UINib nibWithNibName:NSStringFromClass([Cell class]) bundle:nil]; [tableView registerNib:nib forCellReuseIdentifier:CellIdentifier]; nibsRegistered = YES; } Cell *cell = (Cell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; cell.titleLabel.text = [self.dataList objectAtIndex:indexPath.row]; return cell;
我们可以看到,红色部分很好地满足了我们的需求:既从nib加载,又能对cell进行重用。下面对代码进行解释:
1.UINib是一个IOS4.0才出现的类,与MAC上的NSNib类作用相似, 就是加速频繁使用的NIB文件的加载。在第一次从硬盘加载NIB时,它在内存中缓存NIB文件对象。之后加载NIB文件时就会从内存拷贝而避免了较慢的硬盘访问。Apple宣称可以在 加载NIB文件时提供 2倍的速度提升 。 使用UINib的最明显的地方就是在需要在每次创建新Cell时从NIB文件中加载Cell的UITableViewControllers中。UINib的优势就是在不用大量修改代码的情况获得性能改进。其实简单地说,就是利用缓存机制避免了频繁从硬盘中加载XIB文件,这在大数据量的时候显得尤为有用。
2.除了上述代码,还需要在xib文件中做如下设置:在Cell.xib的Inspector窗口中将Identifier进行设置,这里的Identifier要与cellForRowAtIndexPath中一致。
以上就是从xib加载自定义UITableViewCell的注意事项以及解决方案,很多人采用了第二种方法,看起来虽然没问题但是一旦内存吃紧的时候问题就暴露出来了!
之前的代码就是第2种写法,以前也没有仔细考虑过这个问题,今天心血来潮,想到了这个问题,百度一下,才发现果然有问题。