之前我在項(xiàng)目中總是會(huì)遇到這樣的情況:在UITableViewCell中添加了一個(gè)UIButton济瓢,UIButton點(diǎn)擊后觸發(fā)buttonPress:方法,在方法被調(diào)用后需要知道用戶點(diǎn)擊的是哪一個(gè)Cell纸肉。
原來(lái)我的做法是button.tag = indexPath.section 或者 button.tag = indexPath.row,很簡(jiǎn)單 =蔗彤。= 隱約總覺得這種實(shí)現(xiàn)方式不是正規(guī)做法剖毯,但一直也沒想起來(lái)改。
錯(cuò)誤代碼示范堂淡,請(qǐng)勿模仿:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"testCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
UIButton *avatarBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[avatarBtn addTarget:self action:@selector(avatarButtonPress:) forControlEvents:UIControlEventTouchUpInside];
[cell.contentView addSubview:avatarBtn];
}
avatarBtn.tag = indexPath.row; //用button的tag屬性傳遞當(dāng)前cell的row值
//....
}
- (void)avatarButtonPress:(UIButton*)sender
{
int row = sender.tag; //獲得之前設(shè)置的row值
//....
}
今天我發(fā)現(xiàn)了這樣做的弊端馋缅。
我在TableView中需要實(shí)現(xiàn)一個(gè)刪除操作:點(diǎn)擊Cell中的刪除按鈕后扒腕,刪除當(dāng)前行的Cell,使用動(dòng)畫效果萤悴。
我是這樣實(shí)現(xiàn)的:
- (void)deleteButtonPress:(UIButton*)sender
{
int section = sender.tag; //使用tag傳遞Cell的indexPath.section值
[_tableView beginUpdates];
[_tableView deleteSections:[NSIndexSet indexSetWithIndex:section]
withRowAnimation:UITableViewRowAnimationLeft];
[_tableView endUpdates];
}
ok瘾腰,我刪除掉啦,看上去一切良好~
然后程序點(diǎn)擊兩下就崩掉了覆履。蹋盆。。
看了下拋出的異常硝全,說(shuō)代碼中訪問(wèn)了不存在的indexPath.section或row值栖雾。想了想明白了:原來(lái)都是使用UIButton的tag進(jìn)行記錄indexPath值的,但是這種刪除操作執(zhí)行后伟众,UIButton的tag值是不會(huì)更新的析藕,只有在執(zhí)行[_tableView reloadData]方法(或滑動(dòng)列表,這時(shí)會(huì)調(diào)用cellForRowAtIndexPath方法)才能刷新凳厢。
所以這時(shí)TableViewCell中的button.tag值已經(jīng)不對(duì)了噪径!這時(shí)對(duì)Cell做操作,獲得的indexPath值根本不對(duì)数初,程序報(bào)錯(cuò)是必然的找爱。
解決辦法是?
當(dāng)然是使用正規(guī)的辦法獲取indexPath值泡孩!如何做呢车摄?
- (void)deleteButtonPress:(UIButton*)sender
{
//首先獲得Cell:button的父視圖是contentView,再上一層才是UITableViewCell
UITableViewCell *cell = (UITableViewCell *)sender.superview.superview;
//然后使用indexPathForCell方法仑鸥,就得到indexPath了~
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
}
一點(diǎn)思考
使用tag值傳遞indexPath是一種不安全的做法吮播。因?yàn)樗驮贾抵g沒有“強(qiáng)聯(lián)系”。這就像人傳話眼俊,a直接與b交流沒什么問(wèn)題意狠,但a委托j再委托k再委托l(wèi)傳話給b時(shí),就很難保證不出問(wèn)題疮胖。在上述例子中环戈,就是由于tableView列表中的cell發(fā)生變化,而tag存儲(chǔ)的值是“二手?jǐn)?shù)據(jù)”澎灸,因而給后面的代碼傳值出錯(cuò)院塞,導(dǎo)致最終程序崩潰。所以在程序設(shè)計(jì)時(shí)性昭,要盡量避免使用這種“二手?jǐn)?shù)據(jù)”拦止,一來(lái)保證數(shù)據(jù)正確,二來(lái)減少代碼維護(hù)量。
本文轉(zhuǎn)自Tony's blog 原文網(wǎng)址:http://itony.me/258.html