在应用程序委托中返回之前,等待asynchronous任务完成完成块
我正在使用UIManagedDocument
的子类在我的项目中使用核心数据。 重点是子类返回一个单例实例,以便我的屏幕可以简单地调用它,并且托pipe对象上下文对于所有这些实例都保持相同。
在使用UIManagedDocument
之前,我需要打开它,如果它的文件path已经存在,或者创build它,如果它尚未。 我创build了一个方便的方法prepareWithCompletionHandler:
在子类中方便两种场景。
@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
我想要做的就是在我的应用程序委托的didFinishLaunchingWithOptions
调用这个准备方法,然后等待完成块被执行,然后返回YES
或NO
。 我目前的做法是行不通的。
- (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; }
在返回successful
之前,如何等待prepareWithCompletionHandler
的完成处理程序被调用? 我很困惑。
我不确定为什么didFinishLaunching
返回状态依赖于您的完成处理程序的成功,因为您显然甚至不考虑launchOptions
。 我不希望看到你在这里放置一个同步调用(或者更准确地说,使用一个信号量来将一个asynchronous方法转换为一个同步方法),因为它会减慢应用程序的速度,如果速度太慢,看门狗进程。
信号量是使asynchronous进程同步的一种常用技术:
- (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; }
但是,在进一步检查prepareWithCompletionHandler
的工作后,显然是调用方法将自己的完成块分派给主队列,所以任何使这个同步的尝试都会死锁。
所以,使用asynchronous模式。 如果你想在didFinishLaunchingWithOptions
启动它,你可以让它发布一个通知:
- (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; }
然后你可以让你的视图控制器addObserverForName
观察这个通知。
或者,您可以将此代码移出应用程序委托并移入该视图控制器,从而不需要通知。
这里提出了很多使用dispatch_group_wait
或信号量的解决scheme,但真正的解决scheme是重新思考为什么要阻止从didFinishLaunching
返回,直到可能很长的asynchronous请求完成。 如果在操作完成之前确实无法做任何其他操作,我的build议是在初始化发生时显示某种加载请等待屏幕,然后立即从didFinishLaunching返回。
对于你的情况使用调度组将略有不同:
- (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; }