从UITableViewCell引用到父UITableView?

Mic*_*ich 67 iphone cocoa-touch objective-c

有没有办法UITableView从一个内部访问拥有UITableViewCell

jbr*_*nan 117

weak在单元格中存储对tableView 的引用,您将在-tableView:cellForRowAtIndexPath:表格的dataSource中设置该引用.

这比依赖self.superview始终完全是tableView更脆弱更好.谁知道Apple UITableView将来如何重新组织视图层次结构.

  • 为了安全起见,您可能希望添加一个'[self.superview isKindOfClass:[UITableView class]]'检查,以防将来视图层次结构发生变化. (12认同)
  • 是的,他们确实用IOS 7改变了这个:) (4认同)
  • 实际上,这看起来有点像黑客攻击它,因为如果某些表设计首先有一些容器,并且它们包含单元格,在这种情况下,`cell.superview`可能不是表,所以它正在假设这里是UITableView实现 (3认同)
  • 您可以遍历子视图而不依赖于任何特定的视图层次结构,如下面的"类别"中所示.这保证了它将在未来版本中运行.这样,您就不必在代码中分散引用并增加对象耦合. (2认同)
  • @JamesDonald Apple也没有添加"parentTableView"方法,因此不太清楚苹果的动机是什么.在很多情况下,表格不需要引用,因此添加引用会占用字节数.添加引用可能会导致问题,因为人们倾向于引用单元格中的表.配置单元格然后可以在重用单元时无意中调用该表.鉴于代码的简单性,我使用弱引用.使用一点点内存比咀嚼某人不断上升的等级电池更好. (2认同)

DTs*_*DTs 18

这是一种更好的方法,它不依赖于任何特定的UITableView层次结构.它可以与任何未来的iOS版本一起使用,前提是UITableView它不会完全改变类名.这不仅极不可能,但如果真的发生了,你无论如何都要修饰你的代码.

只需导入下面的类别并获取您的参考 [myCell parentTableView]

@implementation UIView (FindUITableView)

-(UITableView *) parentTableView {
    // iterate up the view hierarchy to find the table containing this cell/view
    UIView *aView = self.superview;
    while(aView != nil) {
        if([aView isKindOfClass:[UITableView class]]) {
            return (UITableView *)aView;
        }
        aView = aView.superview;
    }
    return nil; // this view is not within a tableView
}

@end
Run Code Online (Sandbox Code Playgroud)


// To use it, just import the category and invoke it like so:
UITableView *myTable = [myTableCell parentTableView];

// It can also be used from any subview within a cell, from example
// if you have a UILabel within your cell, you can also do:
UITableView *myTable = [myCellLabel parentTableView];

// NOTE:
// If you invoke this on a cell that is not part of a UITableView yet
// (i.e., on a cell that you just created with [[MyCell alloc] init]),
// then you will obviously get nil in return. You need to invoke this on cells/subviews
// that are already part of a UITableView.
Run Code Online (Sandbox Code Playgroud)


更新
评论中有一些讨论是否保持弱引用是一种更好的方法.这取决于你的情况.遍历视图层次结构时会有一些小的运行时损失,因为您正在循环直到识别出目标UIView.你的观点有多深?另一方面,保持对每个单元格的引用具有最小的内存惩罚(弱引用毕竟是一个指针),并且通常在不需要它们的地方添加对象关系被认为是一个糟糕的OO设计实践,原因很多,并且应该应避免(见下面评论中的详细信息).

更重要的是,将表引用保留在单元格内会增加代码复杂性并导致错误,因为UITableViewCells它们是可重用的.UIKit不包括cell.parentTable财产并非巧合.如果您定义自己的代码,则必须添加代码来管理它,如果您没有有效地执行此操作,则可能会引入内存泄漏(即,单元格在其表的生命周期内存活).

因为通常当用户与单元格交互时(单个单元格执行),而不是在布置表格时[tableView:cellForRowAtIndexPath:](对所有可见单元格执行),您将使用上面的类别,运行时成本应该是无关紧要的.

  • @CameronLowellPalmer不,这在iOS7中仍然可以正常工作,它将在未来的iOS版本中继续使用.应用程序商店中的许多应用程序仍然使用此代码没有问题,只需按照代码注释中的建议将其放在正确的位置即可.在所有地方存储引用并不能促进干净的设计,许多设计书籍都表明它是可以避免的. (4认同)
  • @mattcurtis如果你发现自己走过子视图,你应该问问自己,为什么?这个坏主意最好通过iOS 7对UITableViewCell的更改来说明,这将使它始终返回nil.如果您需要从单元格中获取tableview,那么弱引用就是要走的路. (3认同)
  • @CameronLowellPalmer如果您希望读者考虑您的意见,那么证明它是合理的.在没有说明问题的情况下将想法表述为教条,并不能帮助任何人评估它或从中学习.上面的代码是通用的,并没有制动,我提供了评论,以显示弱参考方法的优缺点.如果您有更多的贡献,请详细说明.到目前为止,我们看到的是你没有完全理解上面的代码是如何工作的,因为你错误地声称它在iOS7中不起作用. (3认同)
  • @CameronLowellPalmer优秀的OO设计和特别是Demeter法则规定"单位应该对其他单位只有有限的知识,并且只在绝对必要时这样做".这是为了促进松散的单元耦合和可重用性.保持对子视图的引用实际上违反了LoD,而不是以视图层次结构不可知的方式遍历视图.后者促进了松耦合和良好的OO可重复使用设计,实际上很好地尊重了LoD.也许你不喜欢的是在依赖固定的硬编码层次结构时遍历子视图,而这不是这里的情况. (3认同)
  • @CameronLowellPalmer一个`UITableViewCell`受到'UIKit`设计的限制,生活在`UITableView`下面.以"UIView层次结构 - 不可知"的方式查找**UITableView的**实例不会引入任何其他关系.然后,在软件工程中,`UITableViewCell`被称为"松散耦合".相反,在`UITableViewCell`中维护对特定**`UITableView`实例的引用被认为是紧耦合,因为引入了直接关系.UIKit中没有提供"UITableViewCell.parentTable"属性并非偶然. (3认同)
  • @CameronLowellPalmer如果您认为这里讨论的2个解决方案"实质上相同",我建议学习Apple的"Objective-C编程",这是该语言的优秀入门指南.它应该可以帮助您清除这里讨论的这两个直接相反的解决方案之间的差异.顺便说一句,鉴于OP发布的原始问题只能通过这里讨论的两种竞争方法中的一种来解决,你最后的评论似乎表明OP不应该解决这个常见而简单的问题,而是放弃.这毫无意义. (3认同)
  • @CameronLowellPalmer这开始是一个很好的讨论,但在这一点上很明显,你的观点已经被打败了,你的最后几条评论没有任何意义,他们似乎只服务于"我想赢得这个"的目的.为了我们所有人的利益,所有这段时间都礼貌地回应了+1,我确实从这个论点中学到了很多东西.也许下次你应该尝试减少挑衅性,你的开场评论确实很烦人而不是建设性的.事实证明,你错了. (2认同)

Cul*_*tes 13

Xcode 7 beta,Swift 2.0

这对我来说很好,在我看来它与层次结构或其他什么都没有关系.到目前为止,我对这种方法没有任何麻烦.我已经将它用于许多异步回调(例如,当API请求完成时).

TableViewCell类

class ItemCell: UITableViewCell {

    var updateCallback : ((updateList: Bool)-> Void)? //add this extra var

    @IBAction func btnDelete_Click(sender: AnyObject) {
        let localStorage = LocalStorage()
        if let description = lblItemDescription.text
        {
            //I delete it here, but could be done at other class as well.
            localStorage.DeleteItem(description) 
        }
        updateCallback?(updateList : true)

    }
}
Run Code Online (Sandbox Code Playgroud)

在实现DataSource和Delegate的表视图类中

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell: ItemCell = self.ItemTableView.dequeueReusableCellWithIdentifier("ItemCell") as! ItemCell!
    cell.updateCallback = UpdateCallback //add this extra line
    cell.lblItemDescription?.text = self.SomeList[indexPath.row].Description
    return cell
}

func UpdateCallback(updateTable : Bool) //add this extra method
{
    licensePlatesList = localStorage.LoadNotificationPlates()
    LicenseTableView.reloadData()
}
Run Code Online (Sandbox Code Playgroud)

当然你可以在其中放置任何变量updateCallback并相应地改变它的功能tableView.

有人可能想告诉我它是否可以保存使用,只是为了确定.

  • 好方案!它需要更多的赞成! (2认同)

Ken*_*ner 7

在构造表视图单元格时,必须将引用添加回UITableView.

但是,几乎可以肯定你真正想要的是对你的UITableViewController的引用......它需要相同的东西,在你构建单元格时将它设置为单元格的委托并将其交给表格视图.

如果要进行连接操作,另一种方法是在IB中构建单元格,将表视图控制器作为文件所有者 - 然后将单元格中的按钮连接到表视图控制器中的操作.使用loadNibNamed加载单元格xib时,将视图控制器作为所有者传入,按钮操作将连接回表视图控制器.