gpt4 book ai didi

ios - 了解 AlamoFire OAuth 示例

转载 作者:IT王子 更新时间:2023-10-29 05:30:51 26 4
gpt4 key购买 nike

我能够获得 AlamoFire 提供的 OAuth 示例的有效实现。但是,我希望了解某些代码行及其工作原理。

完整示例:

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 { $0(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 }
  1. [weak self]strongSelfguard 的目的是什么?

        requestsToRetry.append(completion)

    if !isRefreshing {
    refreshTokens { [weak self] succeeded, accessToken, refreshToken in
    guard let strongSelf = self else { return }

    //Implementation

    strongSelf.requestsToRetry.forEach { $0(succeeded, 0.0) }
    strongSelf.requestsToRetry.removeAll()
    }
    }
  2. 这个请求重试是如何工作的? requestsToRetry 只是一个 RequestRetryCompletion = (_ shouldRetry: Bool, _ timeDelay: TimeInterval) 的数组 它如何知道要重试哪些请求?

strongSelf.lock.lock()

  1. 在执行此方法时,NSLock 是否不允许任何其他线程访问 self (OAuth2Handler)?

最佳答案

1) 正如 Fonix 所评论的那样,您对 self 有很强的引用,以避免如果 self 为 nil 您开始收集保留周期..

我是指:

[weak self] ... in
guard let strongSelf = self else { return }

由于 self 将在异步调度的 block 中被捕获, self 将被隐式保留并在 block 完成时再次释放,换句话说 self 将一直延伸到 block 完成之后。编写这段代码,您可以避免延长 self 的生命周期,并决定在 self 等于 nil 时不执行该 block

2)根据你提到的台词:

if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 {
requestsToRetry.append(completion)
..

有一个名为 requestsToRetry 的数组,其中包含您需要重新启动的所有请求。在此代码中,您将所有具有 401 状态代码的请求附加到数组(当服务器返回状态代码 401 时)使用代码 forEach 循环遍历 requestToRetry 数组:

strongSelf.requestsToRetry.forEach { $0(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)
}

您可以找到更多详细信息 here

3) 正如您所说,经常面临的并发问题与从不同线程访问/修改共享资源有关。lock.lock() 是一种在项目被修改时锁定其他执行 block 的解决方案。 defer 中的代码在离开函数以解锁 block 之前被调用。

关于ios - 了解 AlamoFire OAuth 示例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42079180/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com