0
点赞
收藏
分享

微信扫一扫

iOS 不要使用tag传递TableViewCell的indexPath值


 

iOS 不要使用tag传递TableViewCell的indexPath值


之前我在项目中总是会遇到这样的情况:在UITableViewCell中添加了一个UIButton,UIButton点击后触发buttonPress:方法,在方法被调用后需要知道用户点击的是哪一个Cell。

原来我的做法是button.tag = indexPath.section 或者 button.tag = indexPath.row,很简单 =。= 隐约总觉得这种实现方式不是正规做法,但一直也没想起来改。

错误代码示范,请勿模仿:

- 
   ( 
   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,使用动画效果。

我是这样实现的:


- 
   ( 
   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值!如何做呢?

 

- 
   ( 
   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存储的值是“二手数 据”,因而给后面的代码传值出错,导致最终程序崩溃。所以在程序设计时,要尽量避免使用这种“二手数据”,一来保证数据正确,二来减少代码维护量。

之前的错误方法用了好久,到今天才发现……实在是有些惭愧啊。

 

 

 

 

 

 

举报

相关推荐

0 条评论