一 重用機(jī)制簡(jiǎn)介
首先我們需要搞明白為什么要使用重用機(jī)制,它的原理是什么.
無(wú)論是UITableView還是UICollectionView温自,都有許多需要顯示的cell (item), 但是屏幕的大小是有限的,一次只能顯示那么幾個(gè)德迹,如果我們把所有的數(shù)據(jù)全部都加載進(jìn)去,暫時(shí)又看不到,就會(huì)非常浪費(fèi)內(nèi)存.
那么該如何避免這種不必要的內(nèi)存消耗呢胃碾?就是每次只顯示屏幕能放得下的cell的數(shù)據(jù)易稠,在用戶滑動(dòng)屏幕的過(guò)程中,再去加載新的數(shù)據(jù)吟秩,于是就有了cell的重用機(jī)制
重用機(jī)制實(shí)現(xiàn)了數(shù)據(jù)和顯示的分離,并不會(huì)為每個(gè)要顯示的數(shù)據(jù)都創(chuàng)建一個(gè)Cell,一般情況下只創(chuàng)建屏幕可顯示的最大的cell個(gè)數(shù)+1,每當(dāng)有一個(gè)cell從屏幕消失咱扣,就將其放到緩存池中,如果有新的cell出現(xiàn)涵防,就去緩存池中取闹伪,如果緩存池中沒(méi)有,再創(chuàng)建。
---->這種機(jī)制下系統(tǒng)默認(rèn)有一個(gè)可變數(shù)組 NSMutableArray* visiableCells, 用來(lái)保存當(dāng)前顯示的cell. 還有一個(gè)可變字典 NSMutableDictnery* reusableTableCells, 用來(lái)保存可重復(fù)利用的cell. 之所以用字典是因?yàn)榭芍赜玫腸ell有不止一種樣式,我們需要根據(jù)它的reuseIdentifier(重用標(biāo)識(shí)符)來(lái)查找是否有可重用的該樣式的cell.
二 重用機(jī)制簡(jiǎn)介如何解決一些重用cell
1.cell創(chuàng)建使用[tableView cellForRowAtIndexPath:indexPath]
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
// UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //改為以下的方法
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; //根據(jù)indexPath準(zhǔn)確地取出一行偏瓤,而不是從cell重用隊(duì)列中取出
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//...其他代碼
}
將獲得cell的方法從- (UITableViewCell)dequeueReusableCellWithIdentifier:(NSString)identifier 換為-(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath杀怠;重用機(jī)制調(diào)用的就是dequeueReusableCellWithIdentifier這個(gè)方法,方法的意思就是“出列可重用的cell”厅克,因而只要將它換為cellForRowAtIndexPath(只從要更新的cell的那一行取出cell)赔退,就可以不使用重用機(jī)制,因而問(wèn)題就可以得到解決证舟,但是會(huì)浪費(fèi)一些空間硕旗。(不建議使用)
2.不同標(biāo)識(shí)符
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *CellIdentifier = [NSString stringWithFormat:@"Cell%d%d", [indexPath section], [indexPath row]];//以indexPath來(lái)唯一確定cell
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//...其他代碼
}
通過(guò)為每個(gè)cell指定不同的重用標(biāo)識(shí)符(reuseIdentifier)來(lái)解決。重用機(jī)制是根據(jù)相同的標(biāo)識(shí)符來(lái)重用cell的女责,標(biāo)識(shí)符不同的cell不能彼此重用漆枚。于是我們將每個(gè)cell的標(biāo)識(shí)符都設(shè)置為不同,就可以避免不同cell重用的問(wèn)題了抵知。
3.刪除重用cell的所有子視圖
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; //出列可重用的cell
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
else
{
//刪除cell的所有子視圖
while ([cell.contentView.subviews lastObject] != nil)
{
[(UIView*)[cell.contentView.subviews lastObject] removeFromSuperview];
}
}
//...其他代碼
}
這個(gè)方法是通過(guò)刪除重用的cell的所有子視圖墙基,從而得到一個(gè)沒(méi)有特殊格式的cell,供其他cell重用辛藻〉忾伲考慮到內(nèi)存問(wèn)題,cell少得時(shí)候可以每個(gè)都添加標(biāo)識(shí)符,當(dāng)cell重用較多時(shí),考慮內(nèi)存問(wèn)題,建議用刪除cell的所有子視圖方法(做視頻播放的時(shí)候).
4.cell做一個(gè)tag標(biāo)記,對(duì)cell將要展示的差異內(nèi)容進(jìn)行判斷
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath];
cell.myLabel.text = [NSString stringWithFormat:@"我的Label%ld", indexPath.row];
cell.tag = indexPath.row;
if (cell.tag == 5) {
cell.imageVIew.backgroundColor = [UIColor greenColor];
}
if (cell.tag != 5) {
cell.imageVIew.backgroundColor = [UIColor whiteColor];
}
return cell;
}
三 區(qū)分一下重用cell的兩個(gè)方法
//方法一
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
//方法二
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
在iOS文檔中對(duì)方法二有這樣的特殊描述:important
不同之處:
1.方法二中總是返回一個(gè)有效的UITableViewCell
2.方法二的正確使用方法。這里解釋說(shuō)要先進(jìn)行注冊(cè)我們自定義或者通過(guò)nib的類和標(biāo)識(shí)符吱肌,然后再使用方法二進(jìn)行重用痘拆。所以現(xiàn)在我們崩潰的原因就已經(jīng)明確了,問(wèn)題就出在沒(méi)有進(jìn)行先注冊(cè)我們自定義的類和標(biāo)識(shí)符氮墨。(先注冊(cè),就不需要判空操作)
所以....以后使用可以如下
方法一:判空操作
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MeetingReplyBasicCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BasicCell"];
if (!cell) {
cell = [[MeetingReplyBasicCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"BasicCell"];
}
return cell;
}
方法二:注冊(cè)操作
[self.tableView registerClass:[MeetingReplyBasicCell class] forCellReuseIdentifier:@"BasicCell"];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MeetingReplyBasicCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BasicCell" forIndexPath:indexPath];
return cell;
}