bottom bar ios objective-c grand-central-dispatch

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; }