Как я могу использовать 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 ответа

Решение

Это не то, как вы должны использовать DispatchSemaphore,

Пожалуйста , не заставляйте асинхронный код быть синхронным.

Вам нужно будет реорганизовать свой код, чтобы лучше справляться с асинхронной природой того, чего вы пытаетесь достичь.

Обработчик завершения - это более простой и эффективный способ. Если по какой-то причине вы пытаетесь избежать этого, взгляните на PromiseKit или что-то другое, вспомогательную библиотеку async.

Альтернативным предложением было бы вместо обновления ваших токенов перед полетом, обновить их на 401 и затем воспроизвести ваш оригинальный, обновленный запрос.

Я не уверен, что вы подразумеваете под

Звонок не разрешается

но в вашем примере есть пара моментов, на которые стоит обратить внимание.

  • Убедитесь, что authHeaders не инициализируется в основном потоке, поскольку семафор заблокирует ваш пользовательский интерфейс.
  • Единственный способ, которым семафору будет дан сигнал о прекращении ожидания, - это выполнение закрытия завершения. В вашем коде есть различные пути, где закрытие завершения не будет выполнено. В refreshTokens провалившись первым guard или попадание в блок сбоя не приведет к закрытию завершения, поэтому семафор не перестанет ждать.
Другие вопросы по тегам