¿Cómo obtener UITableView de UITableViewCell?

Tengo una UITableViewCell que está vinculada a un objeto y necesito saber si la celda está visible. A partir de la investigación que hice, esto significa que necesito acceder de algún modo al UITableView que lo contiene (a partir de ahí, hay varias formas de verificar si está visible). Entonces me pregunto si UITableViewCell tiene un puntero al UITableView , o si había alguna otra forma de obtener un puntero de la celda.

Para evitar verificaciones de versiones 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 supervista de una UITableViewCell . También UITableView es una supervista de una 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;

Swift 3 extensión

Recursivamente

 extension UIView { func parentView(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 } } 

Antes de iOS7, la supervista de la celda era la UITableView que lo contenía. A partir de iOS7 GM (así que presumiblemente estará en la versión pública también) la supervista de la celda es una UITableViewWrapperView con su superview siendo la 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 reemplazo cell.superview al uso de cell.superview , hace que sea fácil refactorizar su código existente, solo busque y reemplace con [cell relatedTable] , e cell.superview para asegurarse de que si la jerarquía de vista cambia o revierte en el futuro se mostrará inmediatamente en tus pruebas.

Solución # 2: Agregue una referencia débil de UITableView a UITableViewCell

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

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

Si es visible, entonces tiene una supervista. Y … sorpresa … la supervista es un objeto UITableView.

Sin embargo, tener una supervista no es garantía de estar en pantalla. Pero UITableView proporciona métodos para determinar qué celdas son visibles.

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

Actualización para iOS7: Apple ha cambiado la jerarquía de la subvista aquí. Como de costumbre cuando se trabaja con cosas que no están detalladas documentadas, siempre existe el riesgo de que las cosas cambien. Ahorrar mucho es “escalar” la jerarquía de vistas hasta que finalmente se encuentre un objeto UITableView.

Lo que sea que acabes logrando al llamar a la súper vista oa través de la cadena de respuesta será muy frágil. La mejor manera de hacer esto, si las células quieren saber algo, es pasarle un objeto a la célula que responda a algún método que responda a la pregunta que la célula quiere hacer, y hacer que el controlador implemente la lógica de determinar qué responder (de su pregunta, supongo que la célula quiere saber si algo es visible o no).

Creé una categoría en UITableViewCell para obtener su tableView padre:

 @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,

Solución Swift 2.2.

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

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

En tu celda simplemente lo llamas:

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

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

Aquí está la versión de Swift basada en las respuestas anteriores. He generalizado en ExtendedCell para su 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 objeto UITableViewWrapperView es la super UITableViewCell objeto UITableViewCell en iOS7 beta5.

Subclase 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 la respuesta anterior y obtuve el siguiente fragmento.

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

Pasar de una clase ofrece la flexibilidad de atravesar y obtener vistas distintas a UITableView en algunas otras ocasiones.

Mi solución a este problema es similar a otras soluciones, pero usa un for-loop elegante y es corta. También debe ser a prueba 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 superview, intente usar [“UItableViewvariable” visibleCells].

Lo usé en un bucle 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.

Mínimamente probado, 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 tabe

Le sugiero que recorra la jerarquía de vista de esta manera para encontrar el UITableView padre:

 - (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 vistas.

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

 UITableViewCell Internal View Hierarchy Change in iOS 7 Using iOS 6.1 SDK  |  | |  Using iOS 7 SDK  |  | |  | | |  | |  | | |  The new private UITableViewCellScrollView class is a subclass of UIScrollView and is what allows this interaction: ![enter image description here][1] [1]: http://sofes.miximages.com/iphone/C2uJa.gif 

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

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

de @idris answer escribí una expansión para UITableViewCell en 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 }