等待异步任务完成完成块,然后返回应用程序委托 [英] Wait for async task to finish completion block before returning in app delegate

查看:52
本文介绍了等待异步任务完成完成块,然后返回应用程序委托的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用UIManagedDocument的子类在项目中使用Core Data.关键是子类返回一个单例实例,以便我的屏幕可以简单地调用它,并且所有托管对象的上下文都保持不变.

I'm using a subclass of UIManagedDocument to use Core Data in my project. The point is for the subclass to return a singleton instance so that my screens can simply call it and the managed object context remains the same for all of them.

在使用UIManagedDocument之前,我需要通过打开它(如果其文件路径已存在)或通过创建它(如果尚不存在)来进行准备.我在子类中创建了一个便捷方法prepareWithCompletionHandler:,以方便这两种情况.

Before using the UIManagedDocument, I need to prepare it by opening it if its file path already exists, or creating it if it doesn't yet. I created a convenience method prepareWithCompletionHandler: in the subclass to facilitate both scenarios.

@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中调用此准备方法,并在最后返回YESNO之前等待完成块被执行.我目前的方法行不通.

What I'm trying to do is call this preparation method in my app delegate's didFinishLaunchingWithOptions and wait for the completion block to be executed BEFORE returning either YES or NO at the end. My current approach doesn't work.

- (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中的完成处理程序?我真的很困惑.

How can I wait until the completion handler in prepareWithCompletionHandler is called before returning successful? I'm really confused.

推荐答案

我不确定为什么didFinishLaunching返回状态取决于完成处理程序的成功,因为您显然甚至没有考虑launchOptions.我不希望看到您在此处发出同步调用(或更准确地说,是使用信号量将异步方法转换为同步方法),因为它会使应用程序变慢,并且如果它的速度足够慢,您可能会被杀死看门狗过程.

I'm unsure why the didFinishLaunching return status is dependent upon the success of your completion handler as you're not apparently even considering launchOptions. I'd hate to see you put an synchronous call (or more accurately, use a semaphore to convert an asynchronous method into a synchronous one) here, as it will slow down the app and, if its slow enough, you risk being killed by the watch dog process.

信号量是使异步过程同步的一种常用技术:

Semaphores are one common technique for making an asynchronous process synchronous:

- (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的功能时,显然是在调用将自己的完成块分派到主队列的方法,因此任何试图使该同步完成的尝试都会死锁.

But, upon further review of what prepareWithCompletionHandler is doing, it's apparently calling methods that dispatch their own completion blocks to the main queue, so any attempts to make this synchronous will deadlock.

因此,请使用异步模式.如果要在didFinishLaunchingWithOptions中启动此操作,可以让它发布通知:

So, use asynchronous patterns. If you want to initiate this in the didFinishLaunchingWithOptions, you can have it post a notification:

- (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观察此通知.

And you can then have your view controller addObserverForName to observe this notification.

或者,您可以将此代码从应用程序委托中移出,并移至该视图控制器中,从而无需通知.

Alternatively, you can move this code out of the app delegate and into that view controller, eliminating the need for the notification.

这篇关于等待异步任务完成完成块,然后返回应用程序委托的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆