ios - bar - Espere a que la tarea asíncrona finalice el bloque de finalización antes de regresar en el delegado de la aplicación
status bar iphone (3)
Muchas soluciones propuestas aquí utilizan dispatch_group_wait
o semáforos, pero la solución real es reconsiderar por qué quiere bloquear la devolución de didFinishLaunching
hasta que se didFinishLaunching
una solicitud asíncrona posiblemente larga. Si realmente no puede hacer nada útil hasta que finalice la operación, mi recomendación sería mostrar algún tipo de carga, espere la pantalla mientras se realiza la inicialización y luego vuelva inmediatamente de didFinishLaunching.
Estoy usando una subclase de UIManagedDocument
para usar Core Data en mi proyecto. El punto es que la subclase devuelva una instancia de singleton para que mis pantallas puedan simplemente llamarlo y el contexto del objeto administrado permanezca igual para todos ellos.
Antes de usar UIManagedDocument
, necesito prepararlo abriéndolo si ya existe su ruta de acceso al archivo, o crearlo si aún no existe. prepareWithCompletionHandler:
un método de conveniencia prepareWithCompletionHandler:
en la subclase para facilitar ambos escenarios.
@implementation SPRManagedDocument
// Singleton class method here. Then...
- (void)prepareWithCompletionHandler:(void (^)(BOOL))completionHandler
{
__block BOOL successful;
// _exists simply checks if the document exists at the given file path.
if (self.exists) {
[self openWithCompletionHandler:^(BOOL success) {
successful = success;
if (success) {
if (self.documentState != UIDocumentStateNormal) {
successful = NO;
}
}
completionHandler(successful);
}];
} else {
[self saveToURL:self.fileURL forSaveOperation:UIDocumentSaveForCreating completionHandler:^(BOOL success) {
successful = success;
if (success) {
if (self.documentState != UIDocumentStateNormal) {
successful = NO;
}
}
completionHandler(successful);
}];
}
}
@end
Lo que estoy tratando de hacer es llamar a este método de preparación en las aplicaciones didFinishLaunchingWithOptions
del delegado de la didFinishLaunchingWithOptions
y esperar a que se ejecute el bloque de finalización ANTES de devolver YES
o NO
al final. Mi enfoque actual no funciona.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
}];
});
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
return successful;
}
¿Cómo puedo esperar hasta que se prepareWithCompletionHandler
controlador de finalización en prepareWithCompletionHandler
antes de regresar con successful
? Estoy realmente confundido.
No estoy seguro de por qué el didFinishLaunching
retorno de didFinishLaunching
depende del éxito de su controlador de finalización, ya que aparentemente ni siquiera está considerando launchOptions
. No me gustaría ver que realizas una llamada sincrónica (o más exactamente, usa un semáforo para convertir un método asíncrono en uno sincrónico) aquí, ya que ralentizará la aplicación y, si es lo suficientemente lento, corres el riesgo de que te maten. El proceso del perro guardián.
Los semáforos son una técnica común para hacer que un proceso asíncrono sea sincrónico:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
dispatch_semaphore_signal(semaphore);
}];
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
return successful;
}
Pero, al revisar más a fondo lo que está haciendo prepareWithCompletionHandler
, aparentemente está llamando a los métodos que envían sus propios bloques de finalización a la cola principal, por lo que cualquier intento de hacer esto sincrónico se interrumpirá.
Por lo tanto, utilizar patrones asíncronos. Si desea iniciar esto en didFinishLaunchingWithOptions
, puede hacer que publique una notificación:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
[[NSNotificationCenter defaultCenter] postNotificationName:kDocumentPrepared object:nil];
}];
return successful;
}
Y luego puede tener su controlador de vista addObserverForName
para observar esta notificación.
Alternativamente, puede mover este código fuera del delegado de la aplicación y dentro de ese controlador de vista, eliminando la necesidad de la notificación.
Para su caso, el grupo de despacho será ligeramente diferente:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
__block BOOL successful;
SPRManagedDocument *document = [SPRManagedDocument sharedDocument];
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[document prepareWithCompletionHandler:^(BOOL success) {
successful = success;
dispatch_group_leave(group);
}];
}];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
return successful;
}