PDA

Ver la versión completa : [Programación] Duda Xcode con UNavigationViewController



cdrman
16/04/2013, 14:17
Hola, buenos días.

Ayer estaba probando unas cosillas en el Xcode pero no me acaba de funcionar. Resulta que tengo varios Storyboards creados, de este modo consigo tenerlo todo un poco más ordenado.

Tengo un Storyboard principal con un tabbar definido y en una de sus Tabbaritems tengo definidio un UINavigationController. Hasta ahí correcto, si ahora creo una nueva ViewController arrastro del UINavigation... al ViewController y se luego se crea el vínculo "RootViewController". Vale, funciona correcto, pero si resulta que el "RootViewController" lo tengo en otro Storyboard como consigo hacerlo? Lo he probado por código pero no me acaba de funcionar del modo que debería. A alguien se le ocurre algo?

PD: No sé si me he explicado del modo correcto, no domino demasiado la terminología.

Saludos y gracias.

hardyx
16/04/2013, 14:26
Yo lo hago todo por código, supongo que será más sencillo con Storyboards, pero soy de la vieja escuela. También he de decirte que no se entiende cual es el problema. ¿Tienes un RootViewController ya creado en otro lado y no te deja crear uno nuevo? ¿No puedes renombrarlo? Por código te digo que puedes crear lo que quieras en cada item del TabBar sin problemas. Pero intenta que la interfaz sea lo más simple posible, si necesitas usar un Navigation en cada Tabbar quizás la interfaz debería ser un Navigation general con todo, para no hacer un lío al usuario.

cdrman
16/04/2013, 14:33
Hola hardyx.

Ahora no tengo aquí el Mac y no puedo sacar un screenshot del storyboard para que lo veas más claro, pero creo que no es ningún lío para el usuario.
Cada item del tabbar no va a ser un navigationcontroller, hay alguno que sí, y alguno que no. Pues resulta que una de las opciones sí tiene que serlo. ¿Por código como lo harías? Me refiero a detectar que se accede al item 3, por ejemplo, luego se crear el navigationviewcontroller y se carga el root....

Gracias por todo.

hardyx
16/04/2013, 14:44
Lo de la selección no va por código, simplemente en las propiedades el TabBar le dices el tipo de vista que quieres mostrar en cada item, lo asocias a la clase que quieras mostrar (FirstViewController, SecondViewController, o como los tengas creados). Es bastante sencillo, de hecho hay un asistente en el XCode que te crea un proyecto de tipo TabBar, ahí se puede ver en detalle.

cdrman
16/04/2013, 14:48
Sí, pero si este FirstViewController está en otro StoryBoard como lo hago?

hardyx
16/04/2013, 15:00
Ya te digo que no he tocado mucho de Storyboards, ¿no lo puedes juntar todo en uno? Aún así, he leído que tienen sus limitaciones.

Hay mucha gente que habla pestes de ellos, por ejemplo:
Hay una razón razón por la cual los Storyboard son una mala idea, especialmente para el desarrollador novato: sustituyen código por “magia”. Al contrario de la “magia”, el código es visible , inspeccionable y si está bien escrito, fácilmente inteligible.

cdrman
16/04/2013, 15:02
Ya, lo entiendo, pero si el proyecto es muy grande tenerlo todo en el storyboard me resulta complicado, se hace grande y lioso, al menos para mí. Además que cuando pongo muchos controladores en un mismo storyboard se vuelve lento al cargarlo...

hardyx
16/04/2013, 15:40
Creo que vas a tener que cargar esa vista por código y luego lo metes en el navigation. Mira a ver si te sirve esto (en el NavigationController):


UIViewController *controller = [[UIStoryboard storyboardWithNibName:@"Login"] instantiateViewControllerWithId:@"loginvc"];
[self pushViewController:controller animated:YES];

^MiSaTo^
16/04/2013, 16:28
Hay una razón más por lo que no usar nibs ni StoryBoards, (especialmente cuando la app es muy tocha) es lento cargando porque tiene que parsear el XML (al final son plist, ergo xml) y después instanciarlo. La parte del parseo come recursos y creedme que se nota (en aplicaciones tochas).
Por otro lado, si compartes tu código con más gente, es muchísimo más claro verlo por código que ver el StoryBoard y demás.
Nosotros en el trabajo nunca usamos storyboards/nibs por esas razones ;)

hardyx
16/04/2013, 21:16
A mi el StoryBoard me parece como programar con Flash, muy bonito pero al final para cosas no triviales tienes que meter código. :)
Además, el mezclar versiones de un fichero XML tan grande con Subversion entre varias personas tiene que ser doloroso.

cdrman
17/04/2013, 07:02
Hola, buenos días.

Ya sé que no debe ser lo más eficiente del mundo programar con storyboards pero para empezar puede ir bien, creo. Les adjunto una imagen.

32786

Como había comentado tengo un tabbar y luego, una de las opciones, es un navigation. Pero claro, el primer ViewController que va en el navigation esta en otro storyboard. Es eso no lo que no se como arreglar, manteniendo todo el tema de storyboards que tengo ahora, claro.

Muchas gracias.

-----Actualizado-----

Efectivamente Hardyx con tu código he conseguido arreglar el asunto, de todos modos ahora me habéis echo entrar muchas dudas... Jejejjee. Una última cosilla, tengo un método que lo que hace es hacer una consulta a una bd sqlite y la llena de objetos que representan las filas de la base de datos, hasta ahí correcto. En principio la llamada no tarda demasiado pero cuando hay bastantes registros pues ya se nota un poco.

NSMutableArray * list = [Poi getPois: @"WHERE p.`enabled`=1 LIMIT 100"];


El método en cuestión es en el anterior. He probado algunas formas pero no logro ejecutar esta llamada bloqueando la pantalla de usuario con un loading. Estaría bien hacerlo ya que de este modo el usuario está viendo que la aplicación hace algo.

Además, me acabo de dar cuenta que los inserts en la bd sqlite son un poco lentos. Mi aplicación parsea un fichero externo (xml), lo hace rápido, y siguiendo esa información realiza unos inserts en mi bd. Me he dado cuenta que la parse muy rápido pero que los inserts son lentos. Se os ocurre de por qué puede pasar ésto?

Muchas gracias.

^MiSaTo^
17/04/2013, 11:21
Ahí veo varias cosas:
- Siempre, siempre, siempre, siempre, siempre que hagas una operación "grande", siempre hazla en un thread en background. Esto se puede hacer de varias maneras, por ejemplo con un dispatch o con bloques. En ese caso, como has dicho está bien informar al usuario de que estás haciendo algo y bloquear la UI. Simplemente con un spinner encima de tu UI y deshabilitando el resto debería valer.
Tienes un buen tutorial explicando esto aquí http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial
NO uses notificaciones a no ser que sea estrictamente necesario.

- Las BBDD son lentas. Sí, incluso SQLite es lenta. Y comen recursos. Tenlo muy en cuenta para lo que vayas a hacer, sobre todo de cara a tener memory warnings y las consecuencias de los mismos (views que son destruídas en iOS4-5 por ejemplo). Leete bien la documentación de cómo gestiona iOS esos casos.
- XML también es lento parseando (sobre todo en el caso de que sea algo muy grande). En el simulador no lo vas a notar pero en los teléfonos, sobre todo en el 3GS, sí. Siempre que puedas usa JSON, suele dar mucho más rendimiento que XML.

cdrman
17/04/2013, 11:48
Holas!

Sí, lo que me gustaría hacer es meter todas las consultas contra la bd ejecutarlas en background, por ejemplo con un dispatch.
Sé que las bd's son lentas pero tiene que haber algún modo de que las inserciones sean un poco más rápidas, tampoco son nada del otro mundo 400 inserciones de 4 datos. Esto no pasa siempre pero cuando el usuario ejecuta la app por primera vez se realiza una especie de sincronización. He mirado los timmings y el parseo va perfecto pero se hace lento al hacer las inserciones. Miré de mantener la conexión abierta a la bd hasta terminar, abrir y cerrarla, y el tiempo era muy parecido. No sé si algo se me escapa...

^MiSaTo^
17/04/2013, 12:01
Hasta donde yo se, SQLite es lento y punto. Es un teléfono, no un PC, ten eso en cuenta. Los recursos que tienes son muy muy limitados, de verdad.
De todos modos, tampoco puedes dejar la conexión abierta siempre (eso es un memory leak como una casa) ya que... y si de repente tu ViewController es destruído? y si el usuario se va a otra app? Lo mejor es abrir bbdd, hacer X operación, cerrar bbdd.
De todos modos sin ver el código de la app tampoco puedo decirte mucho más. Para qué versión de iOS estás trabajando?

hardyx
17/04/2013, 12:38
Sin saber la cantidad de datos que gestionas es difícil aventurarse, pero te digo que 400 inserciones (líneas al final) en un fichero de texto plano es infinitamente más rápido que 400 inserciones en una estructura de árbol de una BBDD. Yo tengo un proyecto que lee ficheros de texto plano con unas 6000 filas, que además están comprimidos en zip, y va que vuela incluso en un 3GS (que es el que tengo). Yo haría todo el trasiego de datos en listas o diccionarios en memoria y grabaría todo al final en un fichero .plist o incluso en un fichero binario. A no ser que sean una gran cantidad de datos, claro.

cdrman
17/04/2013, 12:47
Sí, es lo que tengo echo ahora, abrir y cerrar. Estoy trabajando para iOS 6.1.

Te adjunto algo de código:


-(BOOL)insertOrUpdateOrDelete2Db {
NSArray * paths = NSSearchPathForDirectoriesInDomains(NSDocumentDire ctory, NSUserDomainMask, YES);
NSString * documentsDirectory = [paths objectAtIndex:0];
NSString * path = [documentsDirectory stringByAppendingPathComponent: UIAppDelegate.db];
static sqlite3 *_db;
sqlite3_stmt * compiledStatement;
NSString * sql = @"";
BOOL ret = NO;

// Creo el insert y lo dejo en la variable SQL

if (sqlite3_open([path UTF8String], &_db) == SQLITE_OK) {
if (sqlite3_prepare_v2(_db,[sql UTF8String],-1, &compiledStatement, NULL) == SQLITE_OK) {
if(sqlite3_step(compiledStatement) == SQLITE_DONE)
{ret = YES;}
else {ret = NO;}
} else { ret = NO; }
if(sqlite3_finalize(compiledStatement) != SQLITE_OK) { NSLog(@"Error!"); }
} else { ret = NO; }

if (sqlite3_close(_db) != SQLITE_OK) { NSLog(@"Error!"); }
return ret;
}


Ya sé que la mejor forma de hacer el insert es con
"sqlite3_bind_text( compiledStatement, 1,[user_id UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text( compiledStatement, 2,[user_name UTF8String], -1, SQLITE_TRANSIENT); ".

pero para hacer pruebas voy un poco más rápido con un NSString a pelo.

Gracias.

hardyx
17/04/2013, 13:39
Espero que no estés abriendo y cerrando la BBDD en cada actualización. Yo haría el close al final de la aplicación, por ejemplo en el dealloc del controlador principal o en el ApplicationDelegate.

^MiSaTo^
17/04/2013, 13:49
Espero que no estés abriendo y cerrando la BBDD en cada actualización. Yo haría el close al final de la aplicación, por ejemplo en el dealloc del controlador principal o en el ApplicationDelegate.

El problema es entonces, qué pasa si se cierra la app o lo que sea a mitad de una actualización de la base de datos?
Yo siempre abro - hago lo que sea - cierro. Aunque tb tengo un DBManager normalmente que suele hacer todas esas cosas, y bueno hace muchísimo que no uso sqlite3, suelo tirar de CoreData que da más rendimiento.

cdrman
17/04/2013, 14:42
Estoy mirando CoreData.... y pinta muy bien! Ahora no tengo tiempo de rehacer todo el proyecto pero cuando tenga me gustaría migrarlo a CoreData ya que según dices va bastante más rápido y ayuda al modelado de la base de datos de forma visual y mucho cómoda. Algún tuto que me recomiendes?

Gracias.

^MiSaTo^
17/04/2013, 15:01
Pues tutos... yo siempre he mirado la documentación de Apple y ya ;) Sino la otra web que te he puesto tiene tb tutoriales muy buenos sobre todo lo relativo a iOS. Eso sí, tampoco merece la pena implementar CoreData si vas a guardar poca cosa.
Piensa tb que, como ha dicho hardyx, si es poca cosa lo mismo te merece la pena guardar en un plist en vez de una BBDD. Cualquier cosa que use una BBDD es pérdida de rendimiento y recursos en el movil

cdrman
17/04/2013, 19:05
He estado mirando el tema de los threads pero no acabo de ver ejemplos suficientemente claros, al menos para mí. Yo tengo la función:

list = [Poi getPois: @"WHERE p.`enabled`=1 LIMIT 100"];

En este caso me gustaría que se ejecutara la consulta bloqueando la UI y mostrando un mensaje de cargando datos, o si no se bloquea la UI al menos ejectuar en background pero saber cuando termina de ejecutarse para hacer algunas cosillas.

He mirado el dispatch_async pero no acabo de entenderlo bien.

Eskema
17/04/2013, 23:50
Pero si usas un fichero no puedes usar las ventajas de una BD, como filtrar y hacer busquedas por esos registros, salvo que cargues el fichero, lo pases a un array y desde ahi hagas "cosas" con el, ¿o me estoy perdiendo algo?