Ios 理解AlamoFire OAuth示例
我能够得到AlamoFire提供的OAuth示例的工作实现。但是,我希望了解某些代码行及其工作原理 完整示例:Ios 理解AlamoFire OAuth示例,ios,swift,oauth,swift3,alamofire,Ios,Swift,Oauth,Swift3,Alamofire,我能够得到AlamoFire提供的OAuth示例的工作实现。但是,我希望了解某些代码行及其工作原理 完整示例: class OAuth2Handler: RequestAdapter, RequestRetrier { private typealias RefreshCompletion = (_ succeeded: Bool, _ accessToken: String?, _ refreshToken: String?) -> Void private let s
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 }
[弱自我]
和强自我
的防护的目的是什么
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()
}
}
requestsToRetry
只是RequestRetryCompletion=(\ushouldretry:Bool,\utimedelay:TimeInterval)的数组。
它如何知道要重试哪些请求strongSelf.lock.lock()
NSLock
是否不允许任何其他线程访问self
(OAuth2Handler)self
,以避免如果self
为零,您就开始收集保留周期
我是指:
[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时)
使用codeforEach
循环通过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)
}
你可以找到更多的细节
3) 正如您所说,经常遇到的并发性问题与从不同线程访问/修改共享资源有关。
lock.lock()
是一种在修改项时锁定其他执行块的解决方案。defer
中的代码在离开函数解锁块之前被调用。1是为了让您获得对self
的强引用,以便以下代码不会尝试使用self
,如果它为nil,因为self
在该上下文中较弱,强引用将在范围结束时发布,因此不会发生保留周期。对阿拉莫菲尔不熟悉,因此无法确定其他人是什么。