Mat*_*ros 34 objective-c grand-central-dispatch ios
我正在使用UIManagedDocument我的项目中使用Core Data 的子类.关键是子类返回一个单例实例,以便我的屏幕可以简单地调用它,并且托管对象上下文对于所有这些实例保持相同.
在使用之前UIManagedDocument,我需要通过打开它来准备它,如果它的文件路径已经存在,或者如果它还没有创建它.我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
Run Code Online (Sandbox Code Playgroud)
我想要做的是在我的app委托中调用这个准备方法,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;
}
Run Code Online (Sandbox Code Playgroud)
我怎么能等到prepareWithCompletionHandler在返回之前调用完成处理程序successful?我真的很困惑.
Rob*_*Rob 44
我不确定为什么didFinishLaunching返回状态取决于您的完成处理程序的成功,因为您显然甚至没有考虑launchOptions.我不想看到你在这里进行同步调用(或更准确地说,使用信号量将异步方法转换为同步方法),因为它会减慢应用程序的速度,如果它足够慢,你可能会被看门狗过程.
信号量是使异步进程同步的一种常用技术:
- (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;
}
Run Code Online (Sandbox Code Playgroud)
但是,在进一步检查prepareWithCompletionHandler正在做什么之后,它显然正在调用将自己的完成块分配给主队列的方法,因此任何使这种同步的尝试都会死锁.
所以,使用异步模式.如果你想在中发起这个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;
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以让视图控制器addObserverForName观察此通知.
或者,您可以将此代码移出应用程序委托并移动到该视图控制器中,从而无需通知.
对于您的情况,使用调度组将略有不同:
- (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;
}
Run Code Online (Sandbox Code Playgroud)
这里有很多建议的解决方案使用dispatch_group_wait信号量或信号量,但真正的解决方案是重新思考为什么要阻止返回,didFinishLaunching直到可能很长的异步请求完成之后。如果在操作完成之前你真的不能做任何有用的事情,我的建议是在初始化发生时显示某种加载请等待屏幕,然后立即从 didFinishLaunching 返回。
| 归档时间: |
|
| 查看次数: |
39412 次 |
| 最近记录: |