cargar json en una tabla y mostrar preloading

433 views
Skip to first unread message

miquelcamps

unread,
Jun 6, 2012, 6:58:35 AM6/6/12
to iosbo...@googlegroups.com
hola,

ando estancado con un tema, a ver si me podéis echar una mano ;)

estoy cargando un json para rellenar una tabla en el evento viewDidLoad

NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];

hasta aqui todo bien, el problema es cuando quiero poner un preloading (SVProgressHUD)

resulta que si muestro el loader [SVProgressHUD show] y cargo el json en viewDidLoad se muestra el preloading se carga justo al cargar la tabla no al hacer la llamada al servidor.

-------

he probado de mostar el preloading en el evento viewDidLoad y cargar el json en el evento viewDidAppear, pero funciona parcialmente. se muestra el preloading, se carga el json, pero luego la tabla no se actualiza [tableView reloadData]; 

-------

si ayuda aclarar como detalle al cargar el json relleno un NSMutableArray *arrayC;

se os ocurre alguna solución?

Pedro Cid

unread,
Jun 6, 2012, 7:08:14 AM6/6/12
to iosbo...@googlegroups.com


Creo que lo que te pasa es que tanto el NSData como la carga del SVProgressHUD se hacen en el main thread. Podrías hacerlo con GCD del tipo

 //Iniciar el progressHUD

    

    dispatch_async(dispatch_get_global_queue(0, 0), ^{

       

        NSData *data= .....

        

        dispatch_async(dispatch_get_main_queue(), ^{

           //parar el SVProgressHUD

            

        });

        

    });


Saludos

Daniel García

unread,
Jun 6, 2012, 7:10:57 AM6/6/12
to iosbo...@googlegroups.com
Justo, tiene toda la pinta. 
Prueba lo que te propone Pedro. GCD es imprescindible en cualquier escenario en el que tengas que pedir datos a internet.

Si sigue sin funcionarte pega el código de tu controlador para poder orientarte mejor.

Un saludo miquel !

Miquel Camps Orteza

unread,
Jun 6, 2012, 8:02:07 AM6/6/12
to iosbo...@googlegroups.com
gracias a todos por responder!


creo que sigue fallando por el [tableView reloadData]

tengo esta función que devuelve el número de filas, pero solo funciona cuando cargo el json en viewDidLoad, si lo cargo por GCD devuelve 0

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

    return[arrayC count];

}

he probado de mover [tableView reloadData];  dentro de  dispatch_async(dispatch_get_global_queue(0, 0), ^{ y en dispatch_async(dispatch_get_main_queue(), ^{ pero igual :/

alguna idea?

Daniel García

unread,
Jun 6, 2012, 9:23:20 AM6/6/12
to iosbo...@googlegroups.com
Miquel , creo que hay algunos conceptos de base de UITableView que no tienes muy claro y te atascan. Si quieres podemos quedar en persona y te explico con detalle todo el ciclo de vida de UITableView y cómo integrar la carga asíncrona CGD.

Es más fácil de lo que parece, pero hasta que no tienes algunos conceptos claros das palos de ciego.

Dime cuándo quieres y lo vemos ;)

A ver si pronto podemos retomar las sesiones de iOS Bootcamp y damos otro repaso a UITableViewController

Pedro Cid

unread,
Jun 7, 2012, 8:27:33 AM6/7/12
to iosbo...@googlegroups.com

Pon algo de código si puedes y te ayudamos más. Supongo que será un problema de cuando asignas valor a arrayC y cuando llamas a reloadData, pero con un poco de código te podría ayudar más.

Javier Soto

unread,
Jun 7, 2012, 10:18:29 PM6/7/12
to iosbo...@googlegroups.com
Estoy de acuerdo con Daniel, lo más importante es entender cómo funciona UITableView, sino estarás un poco dando palos de ciego.

Luego te recomiendo que empieces a separar responsabilidades: el controlador sólo tiene que ocuparse de gestionar la tabla, no de descargar los datos, eso es tarea del modelo.
Te recomiendo que crees otra clase que tenga un método algo así como:

- (void)loadDataWithSuccessCallback:(void (^)(NSDictionary *data))callback

El motivo de usar blocks es porque va a ser una tarea asíncrona: la llamada a ese método no va a acabar cuando acabe la carga de los datos, sino que acabará "inmediatamente". Esto es así porque se va a llamar a ese método desde el "main thread' (por ejemplo, en - (void)viewDidLoad), y si se tarda en devolver de ese método tanto como tarda el request, durante todo ese tiempo la interfaz no responderá, y la aplicación parecerá estar bloqueada. Te recomiendo que leas este documento de Apple para entender todo lo relativo a los blocks y GCD (que es el API en C que nos permite hacer cosas como coger un "block" y decir que queremos que se ejecute asíncronamente en otro hilo): http://developer.apple.com/library/mac/#featuredarticles/BlocksGCD/_index.html


Este método puede usar por ejemplo AFNetworking: https://github.com/AFNetworking/AFNetworking que es un framework para trabajar con todo lo relativo a requests a un servidor. Pero si lo que quieres en este caso es simplemente traerte el contenido de un archivo, puedes hacerlo en ese método directamente. Ejemplo:

- (void)loadDataWithSuccessCallback:(void (^)(NSArray *data))callback

{

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // Lo que hagamos aquí dentro ocurre asíncronamente.

        NSURL *url = [NSURL URLWithString:@"http://abcd.com/somefile.json"];

        NSData *data = [NSData dataWithContentsOfURL:url]; // Ésta es la llamada que bloquea. Esto tarda tanto en ejecutarse como tarde el teléfono en traerse ese archivo de internet.

        

        // Extraemos el diccionario del JSON usando el API de iOS5

        NSArray *dataArray = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];

        dispatch_async(dispatch_get_main_queue(), ^{

            // Ahora pedimos que este otro block se ejecute en el "hilo principal" / main queue (en el de la UI, desde donde nos llamaron al método).

            

            // Llamamos al callback con los datos. Esta forma de trabajar estoy convencido de que te resulta muy familiar a pasar objetos function() en javascript ;)

            callback(dataArray);

        });

        

    }); // Esta llamada a función devuelve inmediatamente el control

}

Y la llamada podría ser algo así:

- (void)viewDidLoad

{

   // Le pedimos a nuestro objeto que descargue los datos

    [self.dataDownloader loadDataWithSuccessCallback:^(NSArray *data) {

       // Cuando ha acabado, asignamos los datos a un property

        self.data = data;

        // Y le pedimos a la tabla que se actualice. En el método cellForRowAtIndexPath: usamos [self.data objectAtIndex:indexPath.row] y listo :)

        [self.tableView reloadData];

    }];

Reply all
Reply to author
Forward
0 new messages