我如何在关闭时使用DispatchSemaphore

时间:2019-04-26 15:41:30

标签: ios swift asynchronous dispatchsemaphore

我有一个看起来像这样的值

   lazy var authHeaders: [String: String] = {
        if shouldTokenBeRefreshed() {
            let semaphore = DispatchSemaphore(value: 0)
            refreshTokens {
                semaphore.signal()
            }
            semaphore.wait()
        }
        return ["Authorization": "Bearer \(module.client.credential.oauthToken)"]
    }()

这个想法是,当请求我的auth headers时,如果我的令牌已过期,我会刷新它,然后返回新值。

func refreshTokens(completion: @escaping () -> Void) {
    guard let token = keychain.get("refresh_token") else { return }

    module.renewAccessToken(
        withRefreshToken: token,
        success: { [weak self] credential, response, parameters in
            guard let self = self else { return }
            self.storeTokens([
                "access_token": credential.oauthToken,
                "refresh_token": credential.oauthRefreshToken
            ])
            completion()
        },
        failure: { error in
            print(error.description)
        })
}

由于这是async操作,因此我尝试使用Semaphore暂停流,因此一旦触发完成块,我就可以使其继续。

但是电话无法解决,我不确定为什么。

2 个答案:

答案 0 :(得分:1)

我不确定您的意思

  

呼叫无法解决

但是在您的示例中有几点需要注意。

  • 请确保未在主线程上初始化authHeaders,因为信号量会阻塞您的UI。
  • 发信号通知信号停止等待的唯一方法是执行完成关闭。您的代码中有多种路径无法执行完成关闭。在refreshTokens中,如果第一个guard失败或失败,则不会执行完成关闭操作,因此信号量不会停止等待。

答案 1 :(得分:1)

这不是您应该使用DispatchSemaphore的方式。

不要强制异步代码同步。

您将需要重构代码,以更好地处理您要实现的异步特性。

完成处理程序是更简单,更有效的方法。如果出于某种原因试图避免这种情况,请查看PromiseKit或其他异步帮助程序库。

另一种建议是,不要在飞行前更新令牌,而是在401上更新令牌,然后重播原始的更新请求。