Reputation: 1017
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?
Upvotes: 8
Views: 13106
Reputation: 2813
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);
});
});
}
Upvotes: 16
Reputation: 119031
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);
Upvotes: 6
Reputation: 38162
The reason is dispatch_async(dispatch_get_main_queue(), ^
does not wait until execution is done. You are probably messing up stuff there. Normally, this is used to update UI asynchronously along with other server content getting downloaded in some other thread. Try using dispatch_sync
instead.
Upvotes: 3