tutorial example efecto create cellforrowat apple iphone objective-c cocoa-touch uitableview

iphone - efecto - uitableview example swift 4



Problema UITableView cuando se usa un delegado/dataSource por separado (4)

Descripción general:

Para comenzar con lo que funciona, tengo un UITableView que se ha colocado en una vista generada por Xcode utilizando Interface Builder. El Propietario de archivo de la vista se establece en una subclase de UIViewController generada en UIViewController . A esta subclase he agregado implementaciones operativas de numberOfSectionsInTableView: tableView:numberOfRowsInSection: y tableView:cellForRowAtIndexPath: y dataSource y delegate están conectadas a esta clase a través del propietario del archivo en Interface Builder.

La configuración anterior funciona sin problemas. El problema ocurre cuando quiero mover el dataSource esta vista de dataSource y delegate -implementaciones en una clase separada, muy probablemente porque hay otros controles en la vista además de la vista de tabla y me gustaría mover el código relacionado con la vista de tabla fuera a su propia clase. Para lograr esto, intento lo siguiente:

  • Cree una nueva subclase de UITableViewController en Xcode
  • Mueva las implementaciones conocidas de numberOfSectionsInTableView: tableView:numberOfRowsInSection: y tableView:cellForRowAtIndexPath: a la nueva subclase
  • Arrastre un UITableViewController al nivel superior del XIB existente en InterfaceBuilder, elimine el UIView / UITableView que se crea automáticamente para este UITableViewController , luego configure la clase UITableViewController para que coincida con la nueva subclase
  • Elimine el UITableView existente de dataSource ya dataSource y delegate conexiones y conéctelas al nuevo UITableViewController

Cuando esté completo, no tengo un UITableView funcionamiento. Terminé con uno de los tres resultados que aparentemente pueden suceder al azar:

  • Cuando se carga UITableView , obtengo un error de tiempo de ejecución que indica que estoy enviando tableView:cellForRowAtIndexPath: a un objeto que no lo reconoce
  • Cuando UITableView carga, el proyecto irrumpe en el depurador sin error
  • No hay ningún error, pero el UITableView no aparece

Con algunas depuraciones y habiendo creado un proyecto básico solo para reproducir este problema, suelo ver la tercera opción anterior (sin error, pero sin una vista de tabla visible). Agregué algunas llamadas NSLog y descubrí que, aunque numberOfSectionsInTableView: y numberOfRowsInSection: ambas son llamadas, cellForRowAtIndexPath: no lo es. Estoy convencido de que me estoy perdiendo algo realmente simple y esperaba que la respuesta sea obvia para alguien con más experiencia que yo. Si esto no resulta ser una respuesta fácil, me gustaría actualizar con algún código o un proyecto de muestra. ¡Gracias por tu tiempo!

Complete los pasos para reproducirse:

  • Cree un nuevo sistema operativo para iPhone, una aplicación basada en vista en Xcode y TableTest
  • Abra TableTestViewController.xib en Interface Builder y arrastre un UITableView a la superficie de vista proporcionada.
  • Conecte el UITableView de dataSource y delegate -outlets al propietario del archivo, que ya debería representar el TableTestViewController . Guarde sus cambios
  • De vuelta en Xcode, agregue el siguiente código a TableTestViewController.m:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { NSLog(@"Returning num sections"); return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { NSLog(@"Returning num rows"); return 1; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSLog(@"Trying to return cell"); static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease]; } cell.text = @"Hello"; NSLog(@"Returning cell"); return cell; }

  • Build and Go, y debería ver aparecer la palabra Hello en UITableView

  • Ahora, para intentar mover la lógica de esta UITableView a una clase separada, primero cree un nuevo archivo en Xcode, elija la subclase UITableViewController y llame a la clase TableTestTableViewController

  • Elimine el fragmento de código anterior de TableTestViewController.m y colóquelo en TableTestTableViewController.m , reemplazando la implementación predeterminada de estos tres métodos con la nuestra.
  • De vuelta en Interface Builder dentro del mismo TableTestViewController.xib -file, arrastre un UITableViewController a la ventana principal de IB y elimine el nuevo objeto UITableView que viene automáticamente con él
  • Establezca la clase para este nuevo UITableViewController en TableTestTableViewController
  • Elimine el origen de dataSource y delegate enlaces del dataSource ya existía anteriormente y vuelva a conectar los mismos dos enlaces al nuevo TableTestTableViewController que creamos.
  • Guarde los cambios, Build and Go, y si obtiene los resultados que UITableView , tenga en cuenta que UITableView ya no funciona correctamente

Solución: con un poco más de solución de problemas y algo de asistencia de los foros de desarrolladores de iPhone , ¡he documentado una solución! La subclase principal UIViewController del proyecto necesita una salida que apunte a la instancia UITableViewController . Para lograr esto, simplemente agregue lo siguiente al encabezado de la vista principal ( TableTestViewController.h ):

#import "TableTestTableViewController.h"

y

IBOutlet TableTestTableViewController *myTableViewController;

Luego, en Interface Builder, conecte la nueva toma de corriente desde File''s Owner a TableTestTableViewController en la ventana principal de IB. No son necesarios cambios en la parte de UI del XIB. Simplemente teniendo este enchufe en su lugar, aunque ningún código de usuario lo use directamente, resuelve el problema por completo. Gracias a quienes han ayudado y acreditado va a BaldEagle en los foros de desarrolladores de iPhone para encontrar la solución.


Acabo de pasar muchas horas tratando de entender por qué una UITableView no aparece cuando la tengo incrustada en una plumilla separada en lugar de en la punta principal. ¡Finalmente encontré su discusión anterior y me di cuenta de que era porque mi UITableViewController no se conservaba! Aparentemente, las propiedades de delegado y de origen de datos de UITableView no están marcadas como "retener", por lo que mi plumín se estaba cargando pero el controlador se estaba volcando ... Y debido a las maravillas de object-c, no recibí ningún mensaje de error de esto ... Todavía no entiendo por qué no se colgó. Sé que he visto "mensaje enviado a lanzado xxx" antes ... ¿por qué no me estaba dando uno de esos?!?

Creo que la mayoría de los desarrolladores asumirían que la estructura que construyen en un constructor de interfaz se mantendría en un contexto más amplio (el Nib) y no estaría sujeta a publicación. Supongo que sé por qué lo hacen ... para que el iPhone pueda soltar y volver a cargar partes de la punta con poca memoria. Pero hombre, eso fue difícil de entender.

¿Puede alguien decirme dónde debería haber leído sobre ese comportamiento en los documentos?

Además, acerca de conectar la vista. Primero, si arrastra uno desde el constructor de UI, verá que conectan la propiedad de vista (que es una IBOutlet ) a la vista de tabla. No es necesario exponer el tableView , que parece establecerse internamente. De hecho, ni siquiera parece necesario establecer la vista a menos que desee la notificación viewDidLoad . Acabo de romper la conexión de visualización entre mi uitableview y uitableviewcontroller (solo delegado y conjunto de uitableviewcontroller datos) y aparentemente funciona bien.


Pude hacer que esto funcionara. Construí un tablero muy bonito con 4 TableViews y una vista web con video. La clave es tener los controladores tableView separados y los IBOutlet a los otros controladores de vista de tabla definidos en el controlador de vista. En UIB solo necesita conectar los otros controladores de vista de tabla al propietario del archivo del controlador de vista. A continuación, conecte las tablas a los controladores de vista correspondientes para la fuente de datos y delegue.


Sí, por algún motivo (sírvase avisar si alguien sabe por qué ...) la propiedad tableView del UITableViewController no está expuesta como IBOutlet a pesar de que es una propiedad pública. Entonces, cuando usa Interface Builder, no puede ver esa propiedad para conectarse a su otra UITableView . Entonces, en su subclase, puede crear una propiedad tableView marcada como IBOutlet y conectar eso.

Todo esto parece chapucero y una solución para mí, pero parece ser la única forma de separar un UITableViewController''s UITableView y colocarlo en otro lugar en la jerarquía de UI. Me encontré con el mismo problema cuando traté de diseñar la vista donde hay cosas distintas de UITableView y esa fue la forma en que lo resolví ... ¿Es este el enfoque correcto?


Seguí tus pasos, recreé el proyecto y encontré el mismo problema. Básicamente estás casi allí. Faltan 2 cosas (una vez arreglado):

  • tableView conectar tableView de TableTestTableViewController a UITableView que tiene en la pantalla. Como dije antes porque no es IBOutlet , puede anular la propiedad tableView y hacerla así como IBOutlet :

    @interface TableTestTableViewController : UITableViewController { UITableView *tableView; } @property (nonatomic, retain) IBOutlet UITableView *tableView;

  • Lo siguiente es agregar una referencia al TableTestTableViewController y retenerlo en TableTestViewController . De lo contrario, su TableTestTableViewController puede ser liberado (después de cargar el plumín sin nada pendiente de él) y es por eso que está viendo resultados erráticos, fallas o que no se muestra nada. Para hacer eso agregue:

    @interface TableTestViewController : UIViewController { TableTestTableViewController *tableViewController; } @property (nonatomic, retain) IBOutlet TableTestTableViewController *tableViewController;

    y conecte eso en el Interface Builder a la instancia TableTestTableViewController .

Con lo anterior, esto funcionó bien en mi máquina.

También creo que sería bueno indicar la motivación detrás de todo esto (en lugar de simplemente usar el UITableViewController con su propia UITableView ). En mi caso, fue para utilizar otras vistas que solo UITableView en la misma pantalla de contenido. De modo que puedo agregar otros UILabels o UIImages en UIView y mostrar UITableView debajo de ellos o encima de ellos.