[转]iOS 不要使用tag传递TableViewCell的indexPath值
2015-06-07 16:13
330 查看
如题。
之前我在项目中总是会遇到这样的情况:在UITableViewCell中添加了一个UIButton,UIButton点击后触发buttonPress:方法,在方法被调用后需要知道用户点击的是哪一个Cell。
原来我的做法是button.tag = indexPath.section 或者 button.tag = indexPath.row,很简单 =。= 隐约总觉得这种实现方式不是正规做法,但一直也没想起来改。
错误代码示范,请勿模仿:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(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属性传递当前cell的row值
//....
}
(void)avatarButtonPress:(UIButton*)sender
{
int row = sender.tag; //获得之前设置的row值
//....
}
今天我发现了这样做的弊端。
我在TableView中需要实现一个删除操作:点击Cell中的删除按钮后,删除当前行的Cell,使用动画效果。
我是这样实现的:
1
2
3
4
5
6
7
8
9
(void)deleteButtonPress:(UIButton*)sender
{
int section = sender.tag; //使用tag传递Cell的indexPath.section值
[_tableView beginUpdates];
[_tableView deleteSections:[NSIndexSet indexSetWithIndex:section]
withRowAnimation:UITableViewRowAnimationLeft];
[_tableView endUpdates];
}
ok,我删除掉啦,看上去一切良好~
然后程序点击两下就崩掉了。。。
看了下抛出的异常,说代码中访问了不存在的indexPath.section或row值。想了想明白了:原来都是使用UIButton的tag进行记录indexPath值的,但是这种删除操作执行后,UIButton的tag值是不会更新的,只有在执行[_tableView reloadData]方法(或滑动列表,这时会调用cellForRowAtIndexPath方法)才能刷新。
所以这时TableViewCell中的button.tag值已经不对了!这时对Cell做操作,获得的indexPath值根本不对,程序报错是必然的。
解决办法是?
当然是使用正规的办法获取indexPath值!如何做呢?
1
2
3
4
5
6
7
8
(void)deleteButtonPress:(UIButton)sender
{
//首先获得Cell:button的父视图是contentView,再上一层才是UITableViewCell
UITableViewCell cell = (UITableViewCell *)sender.superview.superview;
//然后使用indexPathForCell方法,就得到indexPath了~
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
}
一点思考
使用tag值传递indexPath是一种不安全的做法。因为它和原始值之间没有“强联系”。这就像人传话,a直接与b交流没什么问题,但a委托j再委托k再委托l传话给b时,就很难保证不出问题。在上述例子中,就是由于tableView列表中的cell发生变化,而tag存储的值是“二手数据”,因而给后面的代码传值出错,导致最终程序崩溃。所以在程序设计时,要尽量避免使用这种“二手数据”,一来保证数据正确,二来减少代码维护量。
之前的错误方法用了好久,到今天才发现……实在是有些惭愧啊。
原文链接:
之前我在项目中总是会遇到这样的情况:在UITableViewCell中添加了一个UIButton,UIButton点击后触发buttonPress:方法,在方法被调用后需要知道用户点击的是哪一个Cell。
原来我的做法是button.tag = indexPath.section 或者 button.tag = indexPath.row,很简单 =。= 隐约总觉得这种实现方式不是正规做法,但一直也没想起来改。
错误代码示范,请勿模仿:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(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属性传递当前cell的row值
//....
}
(void)avatarButtonPress:(UIButton*)sender
{
int row = sender.tag; //获得之前设置的row值
//....
}
今天我发现了这样做的弊端。
我在TableView中需要实现一个删除操作:点击Cell中的删除按钮后,删除当前行的Cell,使用动画效果。
我是这样实现的:
1
2
3
4
5
6
7
8
9
(void)deleteButtonPress:(UIButton*)sender
{
int section = sender.tag; //使用tag传递Cell的indexPath.section值
[_tableView beginUpdates];
[_tableView deleteSections:[NSIndexSet indexSetWithIndex:section]
withRowAnimation:UITableViewRowAnimationLeft];
[_tableView endUpdates];
}
ok,我删除掉啦,看上去一切良好~
然后程序点击两下就崩掉了。。。
看了下抛出的异常,说代码中访问了不存在的indexPath.section或row值。想了想明白了:原来都是使用UIButton的tag进行记录indexPath值的,但是这种删除操作执行后,UIButton的tag值是不会更新的,只有在执行[_tableView reloadData]方法(或滑动列表,这时会调用cellForRowAtIndexPath方法)才能刷新。
所以这时TableViewCell中的button.tag值已经不对了!这时对Cell做操作,获得的indexPath值根本不对,程序报错是必然的。
解决办法是?
当然是使用正规的办法获取indexPath值!如何做呢?
1
2
3
4
5
6
7
8
(void)deleteButtonPress:(UIButton)sender
{
//首先获得Cell:button的父视图是contentView,再上一层才是UITableViewCell
UITableViewCell cell = (UITableViewCell *)sender.superview.superview;
//然后使用indexPathForCell方法,就得到indexPath了~
NSIndexPath *indexPath = [_tableView indexPathForCell:cell];
}
一点思考
使用tag值传递indexPath是一种不安全的做法。因为它和原始值之间没有“强联系”。这就像人传话,a直接与b交流没什么问题,但a委托j再委托k再委托l传话给b时,就很难保证不出问题。在上述例子中,就是由于tableView列表中的cell发生变化,而tag存储的值是“二手数据”,因而给后面的代码传值出错,导致最终程序崩溃。所以在程序设计时,要尽量避免使用这种“二手数据”,一来保证数据正确,二来减少代码维护量。
之前的错误方法用了好久,到今天才发现……实在是有些惭愧啊。
原文链接:
相关文章推荐
- iOS CoreData详解(七)性能相关
- IOS代码管控APP页面横竖屏切换
- ios动画学习(三)
- 自定义EditText实现类iOS风格搜索框
- vmstat iostat 分析
- iOS中延迟执行的几种方式
- [转]【IOS-博客】IOS牛人博客一览表
- iOS中如何呼出另一个应用
- IOS成长之路-使用xib界面与和代码相关联的方法
- iOS开发之xib技巧介绍
- iOS沙盒(sandbox)机制和文件操作
- GRMustache的使用(HTML模板渲染工具)For iOS
- iOS 数值转换成string
- IOS常用正则表达式
- ios xmpp开发应用后台模式接收聊天信息
- IOS tabbar的显示与隐藏
- iOS添加xib
- 调整控制器支持的方向
- iOS tableView的图片缓存异步加载
- xcode iOS 模拟器 textField 鼠标点击后键盘不显示