ios - sheet - Block_release desasignar objetos de UI en un hilo de fondo
status bar ios (3)
Uno de los patrones presentados en la charla de WWDC 2010 "Bloques y Grand Central Dispatch" fue utilizar llamadas de dispatch_async anidadas para realizar tareas que consumen mucho tiempo en un subproceso en segundo plano y luego actualizar la interfaz de usuario en el subproceso principal una vez que se complete la tarea
dispatch_async(backgroundQueue, ^{
// do something time consuming in background
NSArray *results = ComputeBigKnarlyThingThatWouldBlockForAWhile();
// use results on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[myViewController UpdateUiWithResults:results];
});
});
Dado que "myViewController" se está utilizando dentro de los bloques, automáticamente se "retiene" y luego se libera cuando se limpian los bloques.
Si la llamada de ''liberación'' del bloque es la última llamada de liberación (por ejemplo, el usuario se aleja de la vista mientras se ejecuta la tarea en segundo plano) se llama al método dealloc myViewController, ¡pero se llama en el hilo de fondo!
A los objetos UIKit no les gusta que se desasignen fuera del hilo principal. En mi caso, UIWebView lanza una excepción.
¿Cómo puede este patrón presentado de la WWDC, mencionado específicamente como la mejor manera de evitar el bloqueo de la interfaz de usuario, ser tan defectuoso? ¿Me estoy perdiendo de algo?
En un hilo, solo uso [viewController retain];
luego, al final del hilo, use [viewController release]
. Funciona y no uso GCD~
Esto funcionó para mí (añadió un temporizador):
[self retain]; // this guarantees that the last release will be on the main threaad
dispatch_async(backgroundQueue, ^{
// do something time consuming in background
NSArray *results = ComputeBigKnarlyThingThatWouldBlockForAWhile();
// use results on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
[myViewController UpdateUiWithResults:results];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(releaseMe:) userInfo:nil repeats:NO];
});
});
- (void)releaseMe:(NSTimer *)theTimer {
[self release]; // will be on the main thread
}
Puede usar el calificador de tipo de almacenamiento __block
para tal caso. __block
variables del bloque __block
no son retenidas automáticamente por el bloque. Así que necesitas retener el objeto por ti mismo:
__block UIViewController *viewController = [myViewController retain];
dispatch_async(backgroundQueue, ^{
// Do long-running work here.
dispatch_async(dispatch_get_main_queue(), ^{
[viewController updateUIWithResults:results];
[viewController release]; // Ensure it''s released on main thread
}
});
EDITAR
Con ARC, el objeto retiene automáticamente la variable __block, pero podemos establecer un valor nulo en la variable __block para liberar el objeto retenido cuando lo deseemos.
__block UIViewController *viewController = myViewController;
dispatch_async(backgroundQueue, ^{
// Do long-running work here.
dispatch_async(dispatch_get_main_queue(), ^{
[viewController updateUIWithResults:results];
viewController = nil; // Ensure it''s released on main thread
}
});