Понимание Примера AlamoFire OAuth
я смог получить рабочую реализацию примера OAuth, как это предусмотрено AlamoFire. Тем не менее, я хочу понять определенные строки кода и как он работает.
Полный Пример:
class OAuth2Handler: RequestAdapter, RequestRetrier {
    private typealias RefreshCompletion = (_ succeeded: Bool, _ accessToken: String?, _ refreshToken: String?) -> Void
    private let sessionManager: SessionManager = {
        let configuration = URLSessionConfiguration.default
        configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
        return SessionManager(configuration: configuration)
    }()
    private let lock = NSLock()
    private var clientID: String
    private var baseURLString: String
    private var accessToken: String
    private var refreshToken: String
    private var isRefreshing = false
    private var requestsToRetry: [RequestRetryCompletion] = []
    // MARK: - Initialization
    public init(clientID: String, baseURLString: String, accessToken: String, refreshToken: String) {
        self.clientID = clientID
        self.baseURLString = baseURLString
        self.accessToken = accessToken
        self.refreshToken = refreshToken
    }
    // MARK: - RequestAdapter
    func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
        if let urlString = urlRequest.url?.absoluteString, urlString.hasPrefix(baseURLString) {
            var urlRequest = urlRequest
            urlRequest.setValue("Bearer " + accessToken, forHTTPHeaderField: "Authorization")
            return urlRequest
        }
        return urlRequest
    }
    // MARK: - RequestRetrier
    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 {
                refreshTokens { [weak self] succeeded, accessToken, refreshToken in
                    guard let strongSelf = self else { return }
                    strongSelf.lock.lock() ; defer { strongSelf.lock.unlock() }
                    if let accessToken = accessToken, let refreshToken = refreshToken {
                        strongSelf.accessToken = accessToken
                        strongSelf.refreshToken = refreshToken
                    }
                    strongSelf.requestsToRetry.forEach { (succeeded, 0.0) }
                    strongSelf.requestsToRetry.removeAll()
                }
            }
        } else {
            completion(false, 0.0)
        }
    }
    // MARK: - Private - Refresh Tokens
    private func refreshTokens(completion: @escaping RefreshCompletion) {
        guard !isRefreshing else { return }
        isRefreshing = true
        let urlString = "(baseURLString)/oauth2/token"
        let parameters: [String: Any] = [
            "access_token": accessToken,
            "refresh_token": refreshToken,
            "client_id": clientID,
            "grant_type": "refresh_token"
        ]
        sessionManager.request(urlString, method: .post, parameters: parameters, encoding: JSONEncoding.default)
            .responseJSON { [weak self] response in
                guard let strongSelf = self else { return }
                if 
                    let json = response.result.value as? [String: Any], 
                    let accessToken = json["access_token"] as? String, 
                    let refreshToken = json["refresh_token"] as? String 
                {
                    completion(true, accessToken, refreshToken)
                } else {
                    completion(false, nil, nil)
                }
                strongSelf.isRefreshing = false
            }
    }
}
вопросы:
[weak self] succeeded, accessToken, refreshToken in
                    guard let strongSelf = self else { return }
- 
какова цель
[weak self]иguardнаstrongSelf?requestsToRetry.append(completion) if !isRefreshing { refreshTokens { [weak self] succeeded, accessToken, refreshToken in guard let strongSelf = self else { return } //Implementation strongSelf.requestsToRetry.forEach { (succeeded, 0.0) } strongSelf.requestsToRetry.removeAll() } } как работает повторная попытка запроса? The
requestsToRetry- это просто массивRequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval)как это знаете, какие запросы повторить?
strongSelf.lock.lock()
- тут 
NSLockпросто не позволитself(OAuth2Handler) для доступа к любому другому потоку во время выполнения этого метода? 
1 ответов
1) точно так же, как прокомментировал Fonix, у вас есть сильная ссылка на selfчтобы избежать этого, если self было nil вы начинаете собирать циклы сохранения..
я refeer на :
[weak self] ... in
guard let strongSelf = self else { return }
С self будет захвачен в блоке, который отправляется асинхронно,self будет неявно сохранен и выпущен снова, когда блок будет завершен, другими словами self будет продлен до тех пор, пока блок заканчивается. Делая этот код, вы избегаете продлить срок службы self и решить не выполнять блок, если self равна нулю
2) по линии вы сказали:
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
            requestsToRetry.append(completion)
            ..
есть массив называется requestsToRetry который содержит все запросы, необходимые для перезапуска. В этом коде вы добавляете к массиву все запросы, которые имеют 401 код состояния (когда сервер возвращает код состояния 401)
С кодом forEach цикл requestToRetry время:
strongSelf.requestsToRetry.forEach { (succeeded, 0.0) }
strongSelf.requestsToRetry.removeAll()
и запустить все элементы. После завершения цикла вы удаляете все элементы.
на самом деле, источники сообщают:
public typealias RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) -> Void
public protocol RequestRetrier {
    func should(_ manager: SessionManager, retry request: Request, with error: Error, completion: @escaping RequestRetryCompletion)
}
вы можете найти более подробную информацию здесь
3) точно так же, как вы сказали, часто возникающие проблемы параллелизма связаны с доступом/изменением общего ресурса из разных потоков.
The lock.lock() - это решение для блокировки других блоков выполнения при изменении элементов. Код defer называется просто перед тем, как оставить функцию разблокировки блока.