简体   繁体   中英

dispatch_async in return method Objective-C

I have been trying to use dispatch_async in a method that returns a result. However, I observed that the method returns before executing the dispatch_async block. Due to this I'm not getting the results I expect. Here is some code that demonstrates my problem.

-(BOOL) isContactExists {
    BOOL isContactExistsInXYZ = YES;
    UserId *userId = contact.userId;
    dispatch_async(dispatch_get_main_queue(), ^
    {
        iOSContact *contact = [iOSContact contactForUserId:userId];
        if (nil == contact)
        {
          isContactExistsInXYZ = NO;
        }
    });    

    return isContactExistsInXYZ;
}

This method isContactExists is called somewhere else and based on the response from that method I have to do some stuff. But every time, the value of isContactExistsInXYZ is not what I expect. How do I handle dispatch_async in this situation?

If your going the block route your method needs to look something like this.

- (void)isContactExistsWithCompletionHandler:(void(^)(BOOL exists)) completion 
{
    dispatch_async(dispatch_get_main_queue(), ^
    {
        BOOL isContactExistsInXYZ = YES;
        UserId *userId = contact.userId;
        iOSContact *contact = [iOSContact contactForUserId:userId];
        if (nil == contact)
        {
          isContactExistsInXYZ = NO;
        }
        completion(isContactExistsInXYZ);
    });
}

And where you are calling it something like this.

[someObject isContactExistsWithCompletionHandler:^(BOOL exists) {
    // do something with your BOOL
}];

You should also consider placing your heavy operations in a other que than main. Like this.

- (void)isContactExistsWithCompletionHandler:(void(^)(BOOL exists)) completion 
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
    dispatch_async(queue, ^
    {
        BOOL isContactExistsInXYZ = YES;
        UserId *userId = contact.userId;
        iOSContact *contact = [iOSContact contactForUserId:userId];
        if (nil == contact)
        {
          isContactExistsInXYZ = NO;
        }
        dispatch_async(dispatch_get_main_queue(), ^
        {
            completion(isContactExistsInXYZ);
        });
    });
}

You need to respect that what you are trying to do is asynchronous and embrace that. This means not using a return value. Instead you can write your method to take a callback block as a parameter. Then, when your asynchronous check is complete you can call the block with the result.


So your method signature would become:

- (void)checkIfContactExistsWithCompletion:(ContactExistsBlock)completion {

Where ContactExistsBlock is a block definition with no return and probably a single BOOL parameter.

typedef void (^ContactExistsBlock) (BOOL exists);

原因是dispatch_async(dispatch_get_main_queue(), ^不等到执行完成。你可能搞乱那里的东西。通常,这用于异步更新UI以及其他服务器内容下载到其他一些线程。尝试使用dispatch_sync代替。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM