ios 如何从 UITableViewCell 获取 UITableView?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15711645/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get UITableView from UITableViewCell?
提问by sinθ
I have a UITableViewCell
which is linked to an object and I need to tell if the cell is visible. From the research I've done, this means I need to somehow access the UITableView
that contains it (from there, there are several ways to check if it's visible). So I'm wondering if UITableViewCell
has a pointer to the UITableView
, or if there was any other way to get a pointer from the cell?
我有一个UITableViewCell
链接到一个对象,我需要判断该单元格是否可见。根据我所做的研究,这意味着我需要以某种方式访问UITableView
包含它的内容(从那里,有几种方法可以检查它是否可见)。所以我想知道是否UITableViewCell
有指向 的指针UITableView
,或者是否有任何其他方法可以从单元格中获取指针?
回答by Muhammad Idris
To avoid checking the iOS version, iteratively walk up the superviews from the cell's view until a UITableView is found:
为了避免检查 iOS 版本,从单元格的视图中迭代地向上走超级视图,直到找到 UITableView:
id view = [tableViewCellInstance superview];
while (view && [view isKindOfClass:[UITableView class]] == NO) {
view = [view superview];
}
UITableView *tableView = (UITableView *)view;
回答by KGS-12
In iOS7 beta 5 UITableViewWrapperView
is the superview of a UITableViewCell
. Also UITableView
is superview of a UITableViewWrapperView
.
在 iOS7 beta 5 中UITableViewWrapperView
是一个UITableViewCell
. 也是UITableView
一个UITableViewWrapperView
.
So for iOS 7 the solution is
所以对于 iOS 7 的解决方案是
UITableView *tableView = (UITableView *)cell.superview.superview;
UITableView *tableView = (UITableView *)cell.superview.superview;
So for iOSes up to iOS 6 the solution is
所以对于 iOS 到 iOS 6 的解决方案是
UITableView *tableView = (UITableView *)cell.superview;
UITableView *tableView = (UITableView *)cell.superview;
回答by Orkhan Alikhanov
Swift 5 extension
斯威夫特 5 扩展
Recursively
递归地
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)
}
}
Using loop
使用循环
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
}
}
回答by memmons
Before iOS7, the cell's superview was the UITableView
that contained it. As of iOS7 GM (so presumably will be in the public release as well) the cell's superview is a UITableViewWrapperView
with its superview being the UITableView
. There are two solutions to the problem.
在 iOS7 之前,cell 的 superview 是UITableView
包含它的。从 iOS7 GM 开始(因此大概也会在公开发布中),单元格的超级视图是一个UITableViewWrapperView
,其超级视图是UITableView
. 该问题有两种解决方案。
Solution #1: Create a UITableViewCell
category
解决方案#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
This is a good drop-in replacement to using cell.superview
, makes it easy to refactor your existing code -- just search and replace with [cell relatedTable]
, and throw in an assert to ensure that if the view hierarchy changes or reverts in the future it will show up immediately in your tests.
这是 using 的一个很好的替代品cell.superview
,可以轻松重构现有代码——只需搜索和替换 with [cell relatedTable]
,然后放入断言以确保如果视图层次结构在未来发生变化或恢复,它将立即显示在你的测试中。
Solution #2: Add a Weak UITableView
reference to UITableViewCell
解决方案#2:添加一个弱UITableView
引用UITableViewCell
@interface SOUITableViewCell
@property (weak, nonatomic) UITableView *tableView;
@end
This is a much better design, though it will require a bit more code refactoring to use in existing projects. In your tableView:cellForRowAtIndexPath
use SOUITableViewCell as your cell class or make sure your custom cell class is subclassed from SOUITableViewCell
and assign the tableView to the cell's tableView property. Inside the cell you can then refer to the containing tableview using self.tableView
.
这是一个更好的设计,尽管它需要更多的代码重构才能在现有项目中使用。在您tableView:cellForRowAtIndexPath
使用 SOUITableViewCell 作为您的单元格类时,或确保您的自定义单元格类是从子类化SOUITableViewCell
并将 tableView 分配给单元格的 tableView 属性。在单元格内,您可以使用self.tableView
.
回答by Hermann Klecker
If it is visible then it has a superview. And ... surprise ... the superview is an UITableView object.
如果它是可见的,那么它有一个超级视图。并且......惊喜...... superview 是一个 UITableView 对象。
However, having a superview is no guarantee for being on screen. But UITableView provides methods to determine which cells are visible.
但是,拥有超级视图并不能保证出现在屏幕上。但是 UITableView 提供了确定哪些单元格可见的方法。
And no, there is no dedicated reference from a cell to a table. But when you subclass UITableViewCell you may introduce one and set it upon creation. (I did that myself a lot before I thought of the subview hierarchy.)
不,没有从单元格到表格的专用引用。但是当您继承 UITableViewCell 时,您可能会引入一个并在创建时设置它。(在我想到子视图层次结构之前,我自己做了很多。)
Update for iOS7:Apple has changed the subview hierarchy here. As usual when working with things that are not detailled documented, there is always a risk that things change. It is far saver to "crawl up" the view hierarchy until a UITableView object is eventually found.
iOS7 更新:Apple 在此处更改了子视图层次结构。像往常一样,在处理没有详细记录的事情时,总是有事情发生变化的风险。在最终找到 UITableView 对象之前,“爬上”视图层次结构会节省很多。
回答by Javier Soto
Whatever you may end up managing to do by calling super view or via the responder chain is going to be very fragile. The best way to do this, if the cells wants to know something, is to pass an object to the cell that responds to some method that answers the question the cell wants to ask, and have the controller implement the logic of determining what to answer (from your question I guess the cell wants to know if something is visible or not).
无论您最终通过调用超级视图还是通过响应者链设法做的事情都将非常脆弱。最好的方法是,如果单元格想要知道某事,则将一个对象传递给单元格,该对象响应某个方法来回答单元格想要问的问题,并让控制器实现确定要回答什么的逻辑(从你的问题我猜细胞想知道某些东西是否可见)。
Create a delegate protocol in the cell, set the delegate of the cell the tableViewController and move all the ui "controlling" logic in the tableViewCotroller.
在单元格中创建一个委托协议,将单元格的委托设置为 tableViewController 并在 tableViewCotroller 中移动所有 ui“控制”逻辑。
The table view cells should be dum view that will only display information.
表格视图单元格应该是只显示信息的哑视图。
回答by Mehdzor
Swift 2.2 solution.
Swift 2.2 解决方案。
An extension for UIView that recursively searches for a view with a specific type.
递归搜索具有特定类型的视图的 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
}
}
or more compact (thanks to kabiroberai):
或更紧凑(感谢 kabiroberai):
import UIKit
extension UIView {
func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? {
return superview as? T ?? superview?.superviewOfType(type)
}
}
In your cell you just call it:
在您的单元格中,您只需调用它:
let tableView = self.lookForSuperviewOfType(UITableView)
// Here we go
Mind that UITableViewCell is added on the UITableView only after cellForRowAtIndexPath execution.
注意 UITableViewCell 仅在 cellForRowAtIndexPath 执行后添加到 UITableView 上。
回答by boliva
I created a category on UITableViewCell to get its parent tableView:
我在 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
Best,
最好的事物,
回答by hqt
Here is the Swiftversion based on above answers. I have generalized into ExtendedCell
for later usage.
这是基于上述答案的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
}
}
Hope this help :)
希望这有帮助:)
回答by Azu
I Borrowed and modified a little bit from the above answer and come up with the following snippet.
我从上面的答案中借用并修改了一点,并提出了以下代码段。
- (id)recursivelyFindSuperViewWithClass:(Class)clazz fromView:(id)containedView {
id containingView = [containedView superview];
while (containingView && ![containingView isKindOfClass:[clazz class]]) {
containingView = [containingView superview];
}
return containingView;
}
Passing in class offers the flexibility for traversing and getting views other than UITableView in some other occasions.
在类中传递提供了在其他一些情况下遍历和获取 UITableView 以外的视图的灵活性。