从UITableViewCell引用到父UITableView?
有没有办法从UITableViewCell
访问拥有的UITableViewCell
?
将一个weak
引用存储在单元格中的tableView中,该单元格是在表的dataSource的-tableView:cellForRowAtIndexPath:
设置的。
这比依靠self.superview
总是完全是tableView是脆弱的。 谁知道苹果将来如何重新组织UITableView
的视图层次结构。
这是一个更好的方法,它不依赖于任何特定的UITableView层次结构。 它将与任何未来的iOS版本一起工作,前提是UITableView
不会完全改变classname。 不仅这是不太可能的,但如果它发生,你将不得不润饰你的代码。
只要导入下面的类别,并获取您的参考[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
// 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 // (ie, 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.
UPDATE
关于是否保留弱引用是一个更好的方法,在评论中有一些讨论。 这取决于你的情况。 遍历视图层次结构有一些小的运行时间损失,直到目标UIView被识别为止。 你的观点有多深? 另一方面,保持对每个单元格的引用具有最小的内存损失(弱引用毕竟是一个指针),并且通常在不需要它们的地方添加对象关系被认为是不好的OOdevise实践,并且应该避免(详见下面的评论)。
更重要的是,在单元格内保留表引用会增加代码的复杂性,并可能导致错误,因为UITableViewCells
是可重用的。 UIKit
不包含cell.parentTable
属性并不是巧合。 如果你自己定义你必须添加代码来pipe理它,如果你不能有效地做到这一点,你可以引入内存泄漏(即细胞超过他们的生命周期)。
因为通常当用户与单元格交互(对单个单元格执行)时,您将使用上面的类别,而不是在[tableView:cellForRowAtIndexPath:]
(对所有可见单元格执行)中布置表格时,运行时成本应该是微不足道的。
Xcode 7testing版,Swift 2.0
这对我来说工作得很好,我认为它与层次结构无关。 到目前为止,我对这个方法没有任何问题。 我已经使用了这个许多asynchronouscallback(例如,当一个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) } }
在实现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() }
当然,你可以把任何variables放在updateCallback
并相应地在tableView
改变它的function。
有人可能想告诉我,是否保存使用,只是为了确保。
在构build表视图单元格时,必须将引用添加回UITableView。
但是,几乎可以肯定,你真正想要的是对你的UITableViewController的引用…需要相同的东西,当你build立单元格并将其交给表视图时,将其设置为单元的委托。
另一种方法是,如果要连接操作,则在IB中构build单元格,将表视图控制器作为文件所有者 – 然后将单元中的button连接到表视图控制器中的操作。 当你用loadNibNamed加载单元格xib时,作为所有者传入视图控制器,button操作将被连接回表格视图控制器。
如果您的UITableViewCells具有自定义类,则可以在单元格的标题中添加一个idtypesvariables,并合成该variables。 在加载单元格后设置variables后,您可以自由地使用tableview或任何其他更高级的视图来做任何事情,而没有太多的麻烦或开销。
cell.h
// interface id root; // propery @property (nonatomic, retain) id root;
cell.m
@synthesize根;
tableviewcontroller.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { // blah blah, traditional cell declaration // but before return cell; cell.root = tableView; }
现在,您可以使用根variables从单元格中调用任何tableview的方法。 (例如[root reloadData]);
啊,带我回到闪存编程的美好时光。
其他答案中的两种方法是:(A)存储对表的引用,或(B)走上超级视图。
我总是使用类似于(A)的模型对象和(B)表格单元格。
细胞
如果你正在处理一个UITableViewCell,那么AFAIK你必须拥有UITableView(比如你在一个表格委托方法中),或者处理视图层次结构中的可见单元格。 否则,你可能会做错的事情(请注意“好”)。
单元格被重复使用,如果碰巧有一个不可见,那么单元格存在的唯一真正原因是iOS UITableView的性能优化(一个较慢的iOS版本将会释放,并希望在移出屏幕时释放该单元格)或者因为你有一个具体的参考。 我想这可能是表单元格不赋予tableView实例方法的原因。
所以(B)为所有的iOS提供了正确的结果,以及所有未来的结果,直到它们彻底改变了视图的工作方式。
尽pipe为了避免一遍又一遍地编写泛化代码,我会使用这个:
+(id)enclosingViewOfView:(UIView*)view withClass:(Class)returnKindOfClass { while (view&&![view isKindOfClass:returnKindOfClass]) view=view.superview; return(view); }
和一个方便的方法:
+(UITableView*)tableForCell:(UITableViewCell*)cell { return([self enclosingViewOfView:cell.superview withClass:UITableView.class]); }
(或类别,如果你喜欢)
顺便说一句,如果你关心的是20倍左右的循环对你的应用程序性能的影响,..不。
楷模
如果您正在讨论单元格中显示的模型对象,那么肯定该模型可以/应该知道它的父模型,该模型可能用于查找或触发单元格模型可能的表格(A),但是在将来的iOS更新中不那么脆弱(例如有一天,他们可能会使UITableViewCell复用caching存在于每个复用标识符中,而不是每个tableview的复用标识符),在那一天所有使用弱参考方法会中断)。
Th 模型方法将用于更改单元格中显示的数据(即模型更改),因为更改将传播到模型显示的任何位置(例如,应用程序中的其他某个UIViewController,日志logging…)
单元格方法将用于tableview操作,如果单元格甚至不是表的子视图,那么这可能总是一个坏主意(虽然这是你的代码,坚持下去)。
无论哪种方式,使用unit testing,而不是假设看起来更干净的代码更新iOS时正常工作。
UITableView *tv = (UITableView *) self.superview.superview; UITableViewController *vc = (UITableViewController *) tv.dataSource;