如何从UITableViewCell获取UITableView?
我有一个UITableViewCell
链接到一个对象,我需要告诉如果单元格是可见的。 从我所做的研究中,这意味着我需要以某种方式访问包含它的UITableView
(从那里,有几种方法来检查它是否可见)。 所以我想知道如果UITableViewCell
有一个指向UITableViewCell
的指针,或者如果有任何其他方式从单元格获取指针?
要避免iOS版本检查
id view = [tableViewCellInstance superview]; while (view && [view isKindOfClass:[UITableView class]] == NO) { view = [view superview]; } UITableView *tableView = (UITableView *)view;
在iOS7 beta 5中, UITableViewWrapperView
是UITableViewWrapperView
超级视图。 另外UITableView
是UITableView
的超级视图。
所以对于iOS 7解决scheme是
UITableView *tableView = (UITableView *)cell.superview.superview;
所以对于iOS 6以上的解决scheme
UITableView *tableView = (UITableView *)cell.superview;
在iOS7之前,单元的超级视图是包含它的UITableView
。 从iOS7 GM(大概也将在公开发布中),单元格的超级视图是UITableViewWrapperView
,其超级视图是UITableView
。 有两个解决scheme的问题。
解决scheme#1:创build一个UITableViewCell
类别
@implementation UITableViewCell (RelatedTable) - (UITableView *)relatedTable { if ([self.superview isKindOfClass:[UITableView class]]) return (UITableView *)self.superview; else if ([self.superview.superview isKindOfClass:[UITableView class]]) return (UITableView *)self.superview.superview; else { NSAssert(NO, @"UITableView shall always be found."); return nil; } } @end
这是使用cell.superview
一个很好的替代cell.superview
,可以很容易地重构你现有的代码 – 只需要search和replace[cell relatedTable]
,然后抛出一个断言,以确保如果视图层次结构改变或恢复未来它会立即出现在你的testing中。
解决scheme2:向UITableViewCell
添加一个弱UITableView
引用
@interface SOUITableViewCell @property (weak, nonatomic) UITableView *tableView; @end
这是一个更好的devise,虽然它将需要更多的代码重构,以在现有的项目中使用。 在你的tableView:cellForRowAtIndexPath
使用SOUITableViewCell作为你的单元类,或者确保你的自定义单元类是从SOUITableViewCell
,并将tableView分配给单元格的tableView属性。 在单元格内,可以使用self.tableView
引用包含tableview。
Swift 3扩展
recursion
extension UIView { func parentView<T: UIView>(of type: T.Type) -> T? { guard let view = self.superview else { return nil } return (view as? T) ?? view.parentView(of: T.self) } } extension UITableViewCell { var tableView: UITableView? { return self.parentView(of: UITableView.self) } }
使用循环
extension UITableViewCell { var tableView: UITableView? { var view = self.superview while (view != nil && view!.isKind(of: UITableView.self) == false) { view = view!.superview } return view as? UITableView } }
如果它是可见的,那么它具有超视图。 而…惊喜… superview是一个UITableView对象。
但是,超级观点不能保证在屏幕上。 但是UITableView提供了确定哪些单元格可见的方法。
不,没有从单元格到表格的专用引用。 但是当你inheritanceUITableViewCell时,你可以引入一个并在创build时进行设置。 (我自己做了很多之前,我想到子视图层次结构。)
iOS7更新:苹果已经改变了子视图层次。 像往常一样,处理没有详细logging的事情时,事情总会有变化的风险。 “抓取”视图层次直到最终findUITableView对象是非常节省的。
我在UITableViewCell上创build了一个类来获取它的父级tableView:
@implementation UITableViewCell (ParentTableView) - (UITableView *)parentTableView { UITableView *tableView = nil; UIView *view = self; while(view != nil) { if([view isKindOfClass:[UITableView class]]) { tableView = (UITableView *)view; break; } view = [view superview]; } return tableView; } @end
最好,
无论你通过调用超级视图或通过响应者链可能最终做的事情都将是非常脆弱的。 如果细胞想要知道某件事情,最好的方法就是将一个对象传递给细胞,这个细胞对一些回答细胞想问的问题的方法作出响应,然后让控制器执行确定回答的逻辑(从你的问题,我猜想细胞想知道是否可见或不)。
Swift 2.2解决scheme。
UIView的扩展,recursionsearch具有特定types的视图。
import UIKit extension UIView { func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? { guard let view = self.superview as? T else { return self.superview?.lookForSuperviewOfType(type) } return view } }
或更紧凑(感谢kabiroberai):
import UIKit extension UIView { func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? { return superview as? T ?? superview?.superviewOfType(type) } }
在你的单元格中,你只需要调用它:
let tableView = self.lookForSuperviewOfType(UITableView) // Here we go
请注意,只有在执行cellForRowAtIndexPath之后,UITableViewCell才会添加到UITableView上。
这是基于上述答案的Swift版本。 我已经推广到ExtendedCell
以供以后使用。
import Foundation import UIKit class ExtendedCell: UITableViewCell { weak var _tableView: UITableView! func rowIndex() -> Int { if _tableView == nil { _tableView = tableView() } return _tableView.indexPathForSelectedRow!.row } func tableView() -> UITableView! { if _tableView != nil { return _tableView } var view = self.superview while view != nil && !(view?.isKindOfClass(UITableView))! { view = view?.superview } self._tableView = view as! UITableView return _tableView } }
希望这个帮助:)
我在Gabe的build议基础上解决这个问题, UITableViewWrapperView
对象是iOS7 beta5中UITableViewCell
对象的超级视图。
子类UITableviewCell
:
- (UITableView *)superTableView { return (UITableView *)[self findTableView:self]; } - (UIView *)findTableView:(UIView *)view { if (view.superview && [view.superview isKindOfClass:[UITableView class]]) { return view.superview; } return [self findTableView:view.superview]; }
我从上面的答案借用和修改了一下,并拿出以下代码片段。
- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView { id containingView = [containedView superview]; while (containingView && ![containingView isKindOfClass:[clazz class]]) { containingView = [containingView superview]; } return containingView; }
在类中传递提供了在其他场合下遍历和获取除UITableView以外的视图的灵活性。
我对这个问题的解决scheme有点类似于其他的解决scheme,但是使用一个优雅的for-loop并且很短。 它也应该是未来的certificate:
- (UITableView *)tableView { UIView *view; for (view = self.superview; ![view isKindOfClass:UITableView.class]; view = view.superview); return (UITableView *)view; }
UITableView *tv = (UITableView *) self.superview.superview; BuyListController *vc = (BuyListController *) tv.dataSource;
尝试使用[“UItableViewvariable”visibleCells]来代替superview。
我用foreach循环遍历应用程序看到的单元格,它工作。
for (UITableView *v in [orderItemTableView visibleCells])//visibleCell is the fix. { @try{ [orderItemTableView reloadData]; if ([v isKindOfClass:[UIView class]]) { ReviewOrderTableViewCell *cell = (ReviewOrderTableViewCell *)v; if (([[cell deleteRecord] intValue] == 1) || ([[[cell editQuantityText] text] intValue] == 0)) //code here } } }
奇迹般有效。
最小的testing,但这个非generics的Swift 3的例子似乎工作:
extension UITableViewCell { func tableView() -> UITableView? { var currentView: UIView = self while let superView = currentView.superview { if superView is UITableView { return (superView as! UITableView) } currentView = superView } return nil } }
这个代码`UITableView *tblView=[cell superview];
会给你一个包含tabe视图单元格的UItableview实例
我build议你这样遍历视图层次来查找父UITableView:
- (UITableView *) findParentTableView:(UITableViewCell *) cell { UIView *view = cell; while ( view && ![view isKindOfClass:[UITableView class]] ) { #ifdef DEBUG NSLog( @"%@", [[view class ] description] ); #endif view = [view superview]; } return ( (UITableView *) view ); }
否则,当Apple 再次更改视图层次结构时,代码将会中断。
另一个也遍历层次的答案是recursion的。
UITableViewCell Internal View Hierarchy Change in iOS 7 Using iOS 6.1 SDK <UITableViewCell> | <UITableViewCellContentView> | | <UILabel> Using iOS 7 SDK <UITableViewCell> | <UITableViewCellScrollView> | | <UIButton> | | | <UIImageView> | | <UITableViewCellContentView> | | | <UILabel> The new private UITableViewCellScrollView class is a subclass of UIScrollView and is what allows this interaction: ![enter image description here][1] [1]: http://i.stack.imgur.com/C2uJa.gif
你可以用一行代码得到它。
UITableView *tableView = (UITableView *)[[cell superview] superview];
extension UIView { func parentTableView() -> UITableView? { var viewOrNil: UIView? = self while let view = viewOrNil { if let tableView = view as? UITableView { return tableView } viewOrNil = view.superview } return nil } }