¿Cómo get UITableView de UITableViewCell?

Tengo una UITableViewCell que está vinculada a un object y necesito saber si la celda está visible. De la investigación que he hecho, esto significa que necesito acceder de alguna manera a UITableView que lo contiene (desde allí, hay varias maneras de verificar si es visible). Entonces, me pregunto si UITableViewCell tiene un puntero a UITableView , ¿o si hubiera alguna otra forma de get un puntero de la celda?

Para evitar las comprobaciones de la versión de iOS

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

En iOS7 beta 5 UITableViewWrapperView es la vista de supervisión de UITableViewCell . También UITableView es supervisión de un UITableViewWrapperView .

Entonces, para iOS 7, la solución es

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

Entonces, para iOS, hasta iOS 6, la solución es

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

Antes de iOS7, la supervisión de la celda era UITableView que la contenía. A partir de iOS7 GM (por lo que presumiblemente también se publicará en público), la supervisión de la celda es un UITableViewWrapperView con su supervisión como UITableView . Hay dos soluciones al problema.

Solución # 1: Crear una categoría 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 

Este es un buen reemploop para usar cell.superview , hace que sea más fácil refactorizar su código existente; simplemente busque y reemplace con [cell relatedTable] y haga una cell.superview para asegurarse de que si la jerarquía de vista cambia o revierte en el futuro se mostrará inmediatamente en sus testings.

Solución n. ° 2: Agregar una reference débil UITableView a UITableViewCell

 @interface SOUITableViewCell @property (weak, nonatomic) UITableView *tableView; @end 

Este es un layout mucho mejor, aunque requerirá un poco más de refactorización de código para usar en proyectos existentes. En su tableView:cellForRowAtIndexPath utilice SOUITableViewCell como su class de celda o asegúrese de que su class de celda personalizada esté subclasificada desde SOUITableViewCell y asigne el tableView a la propiedad tableView de la celda. Dentro de la celda, puede consultar la vista de tabla que contiene usando self.tableView .

Swift 3 extensión

Recursivamente

 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) } } 

Usando bucle

 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 } } 

Si es visible, entonces tiene una supervisión. Y … sorpresa … la supervisión es un object UITableView.

Sin embargo, tener una supervisión no es garantía de estar en la pantalla. Pero UITableView proporciona methods para determinar qué celdas son visibles.

Y no, no hay una reference dedicada desde una celda a una tabla. Pero cuando subclasss UITableViewCell puedes introducir uno y configurarlo en la creación. (Lo hice mucho antes de pensar en la jerarquía de subvista.)

Actualización para iOS7: Apple ha cambiado la jerarquía de subvista aquí. Como siempre, cuando se trabaja con cosas que no están documentadas detalladamente, siempre existe el riesgo de que las cosas cambien. Es un gran ahorro para "rastrear" la jerarquía de vista hasta que finalmente se encuentre un object UITableView.

Creé una categoría en UITableViewCell para get su tabla 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 

Mejor,

Lo que sea que termine logrando hacer llamando a súper vista o a través de la cadena de respuesta va a ser muy frágil. La mejor manera de hacerlo, si las celdas quiere saber algo, es pasar un object a la celda que responda a algún método que responda a la pregunta que la celda quiere hacer y hacer que el controller implemente la lógica de determinar qué responder (a partir de su pregunta, supongo que la célula quiere saber si hay algo visible o no).

Solución Swift 2.2

Una extensión para UIView que busca recursivamente una vista con un tipo específico.

 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 } } 

o más compacto (gracias a kabiroberai):

 import UIKit extension UIView { func lookForSuperviewOfType<T: UIView>(type: T.Type) -> T? { return superview as? T ?? superview?.superviewOfType(type) } } 

En tu celular solo lo llamas:

 let tableView = self.lookForSuperviewOfType(UITableView) // Here we go 

Tenga en count que UITableViewCell se agrega en UITableView solo después de la ejecución de cellForRowAtIndexPath.

Aquí está la versión Swift basada en las respuestas anteriores. He generalizado en ExtendedCell para uso posterior.

 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 } } 

Espero que esto ayude 🙂

UITableViewWrapperView esta solución en la sugerencia de Gabe de que el object UITableViewWrapperView es la vista de UITableViewCell object UITableViewCell en iOS7 beta5.

Subclass 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]; } 

Tomé prestado y modifiqué un poco de la respuesta anterior e ideé el siguiente fragment.

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

Pasar en class ofrece la flexibilidad para atravesar y get vistas distintas a UITableView en otras ocasiones.

Mi solución a este problema es algo similar a otras soluciones, pero usa un for-loop elegante y es corto. También debe ser a testing de futuro:

 - (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; 

En lugar de supervise, intente usar ["UItableViewvariable" visibleCells].

Utilicé eso en loops foreach para recorrer las celdas que vio la aplicación y funcionó.

 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 } } } 

Funciona de maravilla.

Probado mínimamente pero este ejemplo no genérico de Swift 3 parece funcionar:

 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 } } 

este código `UITableView *tblView=[cell superview]; le dará una instancia de UItableview que contiene la celda de vista de tabe

Le sugiero que recorra la jerarquía de vistas de esta manera para encontrar el padre 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 ); } 

De lo contrario, su código se romperá cuando Apple vuelva a cambiar la jerarquía de la vista.

Otra respuesta que también atraviesa la jerarquía es recursiva.

 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 gracias

Puede getlo con una línea de código.

 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 } }