Waiting for an asynchronous callback to synchronize

I want to wrap an asynchronous asynchronous SDK transition for synchronization, the code is as follows:

dispatch_semaphore_t sema = dispatch_semaphore_create(0); __block BOOL _isLogined; __block BOOL _isCallback = NO; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^ { //Put your heavy code here it will not block the user interface [[SDKPlatform defaultPlatform] SDKIsLogined:^(BOOL isLogined){ _isLogined = isLogined; _isCallback = YES; dispatch_semaphore_signal(sema); }]; }); while (!_isCallback) { dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); } return _isLogined; 

I already read the question in a similar way. How to wait for the completion of an asynchronous dispatch?

but when it was a call in the user interface thread, a deadlock occurred because the SDK callback also starts a block in the user interface thread.

How to deal with this? Thanks.

+1
asynchronous ios objective-c grand-central-dispatch
source share
1 answer

If the SDKPlatform sends its termination block back to the main queue, your approach of blocking the main thread until the termination block is called is likely to slow down, and you are unlikely to be able to do this. But this semaphore approach is to block the main thread so that you can make the asynchronous method as synchronous, in any case, impractical. In fact, you should use asynchronous templates and use completion block methods in your own code.

This link, How to wait for the asynchronous dispatch to complete? , illustrates how semaphores can be used to synchronously run an asynchronous task. Unfortunately, this technique is misused with alarming frequency. In particular, in this case, the semaphore is not a suitable template in your script, because the semaphore template blocks the main thread, which we should never do in the application.

As a background, the semaphore method works great in the script discussed in this other thread, because this is a completely different technical issue. It is used in a special situation in the framework of testing, and not in the application, and in a situation where (a) the test itself should occur in the main thread; (b) for the testing structure to function, it must block the main thread until the completion of the asynchronous task. In addition, it also works in this test scenario, since the completion block is not executed in the main queue, avoiding the deadlock problem that you encountered.

None of these three conditions are true in your case. Using semaphore technique in your situation is impractical.

So step back and look at your problem. I assume you have a method that looks like this:

 - (BOOL) login { dispatch_semaphore_t sema = dispatch_semaphore_create(0); __block BOOL _isLogined; __block BOOL _isCallback = NO; dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^ { //Put your heavy code here it will not block the user interface [[SDKPlatform defaultPlatform] SDKIsLogined:^(BOOL isLogined){ _isLogined = isLogined; _isCallback = YES; dispatch_semaphore_signal(sema); }]; }); while (!_isCallback) { dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); } return _isLogined; } 

Even if you did not have a dead end problem, this is still the wrong template. What you probably want is something like:

 - (void)loginWithCompletionHandler:(void (^)(BOOL isLoggedIn))completionHandler { [[SDKPlatform defaultPlatform] SDKIsLogined:^(BOOL isLoggedIn){ if (completionHandler) { completionHandler(isLoggedIn); } }]; } 

Note. This function has a return type of void , but the isLoggedIn condition isLoggedIn returned by the completion block (and should only be used in the completion block, for example:

 [self loginWithCompletionHandler:^(BOOL isLoggedIn) { // feel free to use isLoggedIn here }]; // don't try to use isLoggedIn here 
0
source share

All Articles