簡體   English   中英

等待異步回調進行同步

[英]wait an async callback to sync

我想包裝一個SDK異步api進行同步,代碼如下所示:

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;

我已經類似地閱讀了問題, 如何等待異步調度的塊完成?

但是,當它在UI線程中被調用時,會發生死鎖,因為SDK回調也在UI線程中運行了該塊。

怎么處理呢? 謝謝。

如果SDKPlatform將其完成塊分派回主隊列,那么您阻塞主線程直到完成塊被調用的方法肯定會死鎖,對此您無能為力。 但是這種信號量方法阻塞了主線程,因此無論如何,使異步方法表現得像同步方法一樣是不明智的方法。 您實際上應該擁抱異步模式,並在自己的代碼中采用完成塊技術。

該鏈接, 我如何等待異步調度的塊完成? ,說明了如何使用信號量使異步任務同步運行。 可悲的是,該技術被誤用為令人震驚的頻率。 具體來說,在這種情況下,信號量不是您方案中的適當模式,因為信號量模式將阻塞主線程,這是我們絕對不能在應用程序中執行的操作。

作為背景,信號燈技術在另一個線程中討論的場景中很好,因為它是一個非常不同的技術問題。 它是在測試框架而不是應用程序的特殊情況下使用的,並且在以下情況下使用:(a)測試本身必須在主線程上進行; (b)為使測試框架正常運行,它必須阻塞主線程,直到異步任務完成為止。 此外,它也恰好在該測試方案中起作用,因為完成塊不會發生在主隊列上,從而避免了您遇到的死鎖問題。

這三個條件都不適合您的情況。 不建議在您的情況下使用信號量技術。

因此,讓我們退后一步,看看您的問題。 我假設您有一些類似的方法:

- (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;
}

即使您沒有死鎖問題,這仍然是錯誤的模式。 您可能想要的是:

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

注意,此函數具有void返回類型,但是isLoggedIn狀態由完成塊返回(並且應僅在完成塊內使用,如下所示:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM