Reputation: 489
I'm implementing a RequestRetrier with Alamofire to refresh the accessToken of a given user.
func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion) {
lock.lock() ; defer { lock.unlock() }
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
requestsToRetry.append(completion)
if !isRefreshing {
refreshToken(completion: { [weak self] succeded, accessToken in
guard let strongSelf = self else { return }
strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() }
strongSelf.requestsToRetry.forEach{ $0(succeded, 0.0) }
strongSelf.requestsToRetry.removeAll()
})
}
} else {
completion(false, 0.0)
}
}
When strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() }
is called it doesn't continue the execution so I have an infinite loop. I tried checking the result of strongSelf.lock.try()
and returns false.
This is happening when I sign in with a wrong password so the server returns a 401.
This is my refreshToken code
guard !isRefreshing else { return }
// ... Get user ... //
if let user = user {
isRefreshing = true
signIn(user: userDTO)
.subscribe(onNext: { [weak self] userSession in
guard let strongSelf = self else { return }
// ... Save accessToken ... //
completion(true, userSession.accessToken)
strongSelf.isRefreshing = false
}, onError: { [weak self] error in
guard let strongSelf = self else { return }
// ... Log out user ... //
completion(false, nil)
strongSelf.isRefreshing = false
})
.disposed(by: bag)
} else {
completion(false, nil)
}
Upvotes: 4
Views: 868
Reputation: 489
As seen in the Github issue https://github.com/Alamofire/Alamofire/issues/2544 I could fix this by changing:
private let lock = NSLock()
to
private let lock = NSRecursiveLock()
The difference between them is that the recursive lock can by unlocked if the same thread is trying to lock.
Upvotes: 1