No entiende mucho el modelo de subprocesamiento y es probable que se pegue un tiro en el pie si comienza a agregar código asíncrono sin comprender realmente lo que está sucediendo.
El código que escribió se ejecuta en el subproceso principal de la aplicación. Pero cuando lo piensas, no tienes que escribir la función main
; solo implementas el delegado de la aplicación y las devoluciones de eventos (como los controladores táctiles) y de alguna manera se ejecutan automáticamente cuando llega el momento. Esto no es una magia, este es simplemente un objeto Cocoa llamado Run Loop.
Run Loop es un objeto que recibe todos los eventos, procesa los temporizadores (como en NSTimer
) y ejecuta su código. Lo que significa que cuando, por ejemplo, hacer algo cuando el usuario pulsa un botón, el árbol de llamadas se ve un poco como esto:
main thread running
main run loop
// fire timers
// receive events — aha, here we have an event, let’s call the handler
view::touchesBegan…
// use tapped some button, let’s fire the callback
someButton::touchUpInside
yourCode
Ahora yourCode
hace lo que quiere hacer y el bucle de ejecución continúa en funcionamiento. Pero cuando el código tarda demasiado en finalizar, como en su caso, Run Loop debe esperar y, por lo tanto, los eventos no se procesarán hasta que el código finalice. Esto es lo que ves en tu aplicación.
Para resolver la situación, debe ejecutar la operación larga en otra secuencia. Esto no es muy difícil, pero tendrá que pensar en algunos problemas potenciales, sin embargo.Correr en otro hilo puede ser tan fácil como llamar performSelectorInBackground
:
[appDelegate performSelectorInBackground:@selector(GetApps) withObject:nil];
Y ahora hay que pensar en una manera de decirle a la aplicación de los datos se ha cargado, como el uso de una notificación o llamar a un selector de la principal hilo. Por cierto: almacenar los datos en el delegado de la aplicación (o incluso usar el delegado de la aplicación para cargar los datos) no es una solución muy elegante, pero esa es otra historia.
Si elige la solución performSelectorInBackground
, consulte una pregunta relacionada con memory management in secondary threads. Necesitarás tu propio grupo de autorreleases para que no se filtren objetos liberados automáticamente.
Actualización de la respuesta después de algún tiempo - hoy en día por lo general es mejor para ejecutar el código en el fondo utilizando Grand Central Dispatch:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// No explicit autorelease pool needed here.
// The code runs in background, not strangling
// the main run loop.
[self doSomeLongOperation];
dispatch_sync(dispatch_get_main_queue(), ^{
// This will be called on the main thread, so that
// you can update the UI, for example.
[self longOperationDone];
});
});
Sí, leí sobre estas cosas, todavía hay mucho más que entender, pero lo entenderé, me has puesto en la dirección correcta. Gracias. Estaba usando el componente TBXML, así que supongo que necesito escribir uno simple para entender cómo funciona. de todos modos, Otra pregunta relacionada fue, si el usuario elige cerrar la vista, ¿hay alguna forma de terminar la llamada selectorInBackground? en ViewDidUnload ..? – Sam
Eso depende. En casos simples, puede ignorar el problema y codificar la parte de notificación para que no se rompa cuando la vista se cierre antes. Se puede escribir una solución más a prueba de balas usando el modo asíncrono 'NSURLConnection' o la cola de operaciones, ambos tienen un método para cancelar la operación en progreso. – zoul
El último fragmento de código es increíble, es exactamente lo que estoy buscando. ¡Muchas gracias! – kisileno