Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 理解AlamoFire OAuth示例_Ios_Swift_Oauth_Swift3_Alamofire - Fatal编程技术网

Ios 理解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

我能够得到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 }
  • [弱自我]
    强自我
    防护的目的是什么

        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)
  • 1) 正如Fonix所评论的,您强烈地引用了
    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时) 使用code
    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)
    }
    
    你可以找到更多的细节

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

    1是为了让您获得对
    self
    的强引用,以便以下代码不会尝试使用
    self
    ,如果它为nil,因为
    self
    在该上下文中较弱,强引用将在范围结束时发布,因此不会发生保留周期。对阿拉莫菲尔不熟悉,因此无法确定其他人是什么。