102

我有一个UITableViewCell链接到一个对象的,我需要判断单元格是否可见。根据我所做的研究,这意味着我需要以某种方式访问UITableView​​包含它的内容(从那里,有几种方法可以检查它是否可见)。所以我想知道是否UITableViewCell有指向 的指针UITableView,或者是否有任何其他方法可以从单元格中获取指针?

4

21 回答 21

157

为了避免检查 iOS 版本,从单元格的视图迭代地向上遍历超级视图,直到找到 UITableView:

Objective-C

id view = [cellInstance superview];

while (view && [view isKindOfClass:[UITableView class]] == NO) {
    view = [view superview]; 
}

UITableView *tableView = (UITableView *)view;

迅速

var view = cellInstance.superview
while (view != nil && (view as? UITableView) == nil) {
  view = view?.superview
}
        
if let tableView = view as? UITableView {
   tableView.beginUpdates()
   tableView.endUpdates()
}
于 2013-09-13T06:59:52.263 回答
48

在 iOS7 beta 5UITableViewWrapperView中是一个UITableViewCell. 也是UITableViewa的superview UITableViewWrapperView

所以对于iOS 7,解决方案是

UITableView *tableView = (UITableView *)cell.superview.superview;

所以对于 iOS 到 iOS 6 的解决方案是

UITableView *tableView = (UITableView *)cell.superview;

于 2013-08-23T16:53:29.633 回答
43

斯威夫特 5 扩展

递归

extension UIView {
    func parentView<T: UIView>(of type: T.Type) -> T? {
        guard let view = superview else {
            return nil
        } 
        return (view as? T) ?? view.parentView(of: T.self)
    }
}

extension UITableViewCell {
    var tableView: UITableView? {
        return parentView(of: UITableView.self)
    }
}

使用循环

extension UITableViewCell {
    var tableView: UITableView? {
        var view = superview
        while let v = view, v.isKind(of: UITableView.self) == false {
            view = v.superview
        }
        return view as? UITableView
    }
}
于 2017-01-29T11:24:55.643 回答
25

在 iOS7 之前,cell 的 superview 是UITableView包含它的。从 iOS7 GM 开始(大概也将在公开版本中),单元格的超级视图是 a UITableViewWrapperView,其超级视图是UITableView. 该问题有两种解决方案。

解决方案 #1:创建一个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

这是一个很好的替代 using cell.superview,可以轻松重构现有代码 - 只需搜索和替换 with [cell relatedTable],并输入一个断言以确保如果视图层次结构在未来发生更改或恢复,它将立即显示在你的测试中。

解决方案#2:添加一个弱UITableView引用UITableViewCell

@interface SOUITableViewCell

   @property (weak, nonatomic) UITableView *tableView;

@end

这是一个更好的设计,尽管它需要更多的代码重构才能在现有项目中使用。在您tableView:cellForRowAtIndexPath使用 SOUITableViewCell 作为您的单元格类或确保您的自定义单元格类从子类SOUITableViewCell化并将 tableView 分配给单元格的 tableView 属性。在单元格内,您可以使用self.tableView.

于 2013-09-15T14:33:53.693 回答
7

如果它是可见的,那么它有一个超级视图。而且......惊喜......超级视图是一个 UITableView 对象。

但是,拥有超级视图并不能保证出现在屏幕上。但是 UITableView 提供了确定哪些单元格可见的方法。

不,没有从单元格到表格的专用引用。但是当你继承 UITableViewCell 时,你可以引入一个并在创建时设置它。(在我想到子视图层次结构之前,我自己做了很多。)

iOS7 更新: Apple 在此处更改了子视图层次结构。像往常一样,在处理没有详细记录的事情时,总是存在事情发生变化的风险。在最终找到 UITableView 对象之前,“爬上”视图层次结构要省事得多。

于 2013-03-29T21:32:08.223 回答
7

无论您最终通过调用超级视图或通过响应者链设法完成的工作都将非常脆弱。做到这一点的最好方法,如果细胞想知道一些事情,就是将一个对象传递给细胞,该对象响应某种方法来回答细胞想问的问题,并让控制器实现确定要回答什么的逻辑(从你的问题我猜细胞想知道某些东西是否可见)。

在单元格中创建一个委托协议,将单元格的委托设置为 tableViewController 并将所有 ui“控制”逻辑移动到 tableViewCotroller 中。

表格视图单元格应该是只显示信息的虚拟视图。

于 2013-03-29T22:43:35.310 回答
7

斯威夫特 2.2 解决方案。

UIView 的扩展,它递归地搜索具有特定类型的视图。

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

请注意 UITableViewCell 仅在 cellForRowAtIndexPath 执行后才添加到 UITableView 上。

于 2016-08-10T14:58:35.073 回答
6

我在 UITableViewCell 上创建了一个类别来获取其父 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

最好的,

于 2013-09-28T00:47:28.793 回答
3

这是基于上述答案的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
    }
}

希望这有帮助:)

于 2016-04-17T08:30:32.280 回答
2

我基于 Gabe 的建议UITableViewWrapperViewobject is the superview of UITableViewCellobject in iOS7 beta5 这个解决方案。

子类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];
}
于 2013-08-22T03:42:13.090 回答
2

我从上面的答案中借用和修改了一点,并提出了以下片段。

- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
    id containingView = [containedView superview];
    while (containingView && ![containingView isKindOfClass:[clazz class]]) {
        containingView = [containingView superview];
    }
    return containingView;
}

传入类提供了在某些其他情况下遍历和获取 UITableView 以外的视图的灵活性。

于 2014-07-29T06:58:37.517 回答
2

我对这个问题的解决方案与其他解决方案有些相似,但使用了优雅的 for 循环并且很短。它也应该是面向未来的:

- (UITableView *)tableView
{
    UIView *view;
    for (view = self.superview; ![view isKindOfClass:UITableView.class]; view = view.superview);
    return (UITableView *)view;
}
于 2014-08-18T20:17:34.880 回答
2
UITableView *tv = (UITableView *) self.superview.superview;
BuyListController *vc = (BuyListController *) tv.dataSource;
于 2015-07-01T08:27:41.243 回答
1

尝试使用 ["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 
    }
  }
}

奇迹般有效。

于 2013-12-09T18:52:15.923 回答
1

最低限度的测试,但这个非通用 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
    }
}
于 2016-11-09T20:49:30.073 回答
0

此代码`UITableView *tblView=[cell superview];将为您提供 UItableview 的实例,其中包含 tabe 视图单元

于 2013-04-02T07:49:23.273 回答
0

我建议你以这种方式遍历视图层次结构来找到父 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再次更改视图层次结构时,您的代码将中断。

另一个遍历层次结构的答案是递归的。

于 2013-09-01T17:26:47.420 回答
0
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

http://www.curiousfind.com/blog/646 谢谢

于 2014-05-28T08:27:32.007 回答
0

你可以用一行代码得到它。

UITableView *tableView = (UITableView *)[[cell superview] superview];
于 2016-06-13T07:36:35.593 回答
0
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
    }
}
于 2016-08-19T20:05:45.540 回答
0

from @idris answer I wrote an expansion for UITableViewCell in Swift

extension UITableViewCell {
func relatedTableView() -> UITableView? {
    var view = self.superview
    while view != nil && !(view is UITableView) {
        view = view?.superview
    }

    guard let tableView = view as? UITableView else { return nil }
    return tableView
}
于 2018-01-04T09:37:49.233 回答