Как я могу использовать DispatchSemaphore с закрытием - PullRequest
0 голосов
/ 26 апреля 2019

У меня есть значение, которое выглядит следующим образом

   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 ]

1 голос
/ 27 апреля 2019

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

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

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

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

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

1 голос
/ 26 апреля 2019

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

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

но в вашем примере нужно отметить пару вещей.

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