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:
ytableView:cellForRowAtIndexPath:
a la nueva subclase - Arrastre un
UITableViewController
al nivel superior del XIB existente en InterfaceBuilder, elimine elUIView
/UITableView
que se crea automáticamente para esteUITableViewController
, luego configure la claseUITableViewController
para que coincida con la nueva subclase - Elimine el
UITableView
existente dedataSource
yadataSource
ydelegate
conexiones y conéctelas al nuevoUITableViewController
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 enviandotableView: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 unUITableView
a la superficie de vista proporcionada. - Conecte el
UITableView
dedataSource
ydelegate
-outlets al propietario del archivo, que ya debería representar elTableTestViewController
. 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
enUITableView
Ahora, para intentar mover la lógica de esta
UITableView
a una clase separada, primero cree un nuevo archivo en Xcode, elija la subclaseUITableViewController
y llame a la claseTableTestTableViewController
- Elimine el fragmento de código anterior de
TableTestViewController.m
y colóquelo enTableTestTableViewController.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 unUITableViewController
a la ventana principal de IB y elimine el nuevo objetoUITableView
que viene automáticamente con él - Establezca la clase para este nuevo
UITableViewController
enTableTestTableViewController
- Elimine el origen de
dataSource
ydelegate
enlaces deldataSource
ya existía anteriormente y vuelva a conectar los mismos dos enlaces al nuevoTableTestTableViewController
que creamos. - Guarde los cambios, Build and Go, y si obtiene los resultados que
UITableView
, tenga en cuenta queUITableView
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
conectartableView
deTableTestTableViewController
aUITableView
que tiene en la pantalla. Como dije antes porque no esIBOutlet
, puede anular la propiedadtableView
y hacerla así comoIBOutlet
:@interface TableTestTableViewController : UITableViewController { UITableView *tableView; } @property (nonatomic, retain) IBOutlet UITableView *tableView;
Lo siguiente es agregar una referencia al
TableTestTableViewController
y retenerlo enTableTestViewController
. De lo contrario, suTableTestTableViewController
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.