美文网首页
Alamofire 5.0.0-beta.7 源码阅读(一)

Alamofire 5.0.0-beta.7 源码阅读(一)

作者: 奴良 | 来源:发表于2019-08-05 17:33 被阅读0次

    首先我们先看一下最简单的一个请求方法

    public static func request(_ url: URLConvertible,
                                   method: HTTPMethod = .get,
                                   parameters: Parameters? = nil,
                                   encoding: ParameterEncoding = URLEncoding.default,
                                   headers: HTTPHeaders? = nil,
                                   interceptor: RequestInterceptor? = nil) -> DataRequest
    

    解读一下各个参数的意思:

    url

    我们可以看到url的参数类型为URLConvertible,点进去看一下会看到这是一个协议类型,定义如下

    /// Types adopting the `URLConvertible` protocol can be used to construct `URL`s, which can then be used to construct
    /// `URLRequests`.
    public protocol URLConvertible {
        /// Returns a `URL` from the conforming instance or throws.
        ///
        /// - Returns: The `URL` created from the instance.
        /// - Throws:  Any error thrown while creating the `URL`.
        func asURL() throws -> URL
    }
    

    swift中通过extension可以对协议进行默认实现,Alamofire中对StringURL两个类实现了该协议,并添加默认实现如下

    extension String: URLConvertible {
        /// Returns a `URL` if `self` can be used to initialize a `URL` instance, otherwise throws.
        ///
        /// - Returns: The `URL` initialized with `self`.
        /// - Throws:  An `AFError.invalidURL` instance.
        public func asURL() throws -> URL {
            guard let url = URL(string: self) else { throw AFError.invalidURL(url: self) }
    
            return url
        }
    }
    
    extension URL: URLConvertible {
        /// Returns `self`.
        public func asURL() throws -> URL { return self }
    }
    

    method

    请求类型,为一个enum

    public enum HTTPMethod: String {
        /// `CONNECT` method.
        case connect = "CONNECT"
        /// `DELETE` method.
        case delete  = "DELETE"
        /// `GET` method.
        case get     = "GET"
        /// `HEAD` method.
        case head    = "HEAD"
        /// `OPTIONS` method.
        case options = "OPTIONS"
        /// `PATCH` method.
        case patch   = "PATCH"
        /// `POST` method.
        case post    = "POST"
        /// `PUT` method.
        case put     = "PUT"
        /// `TRACE` method.
        case trace   = "TRACE"
    }
    

    parameters 及 headers

    请求参数及请求头
    Parameters我们可以看到实际上是一个别名public typealias Parameters = [String: Any]
    HTTPHeaders为一个结构体,持有一个[HTTPHeader]的数组,我们可以通过HTTPHeader的构造方法来创建header参数。
    HTTPHeaders提供了一些默认header

    public extension HTTPHeaders {
        /// The default set of `HTTPHeaders` used by Alamofire. Includes `Accept-Encoding`, `Accept-Language`, and
        /// `User-Agent`.
        static let `default`: HTTPHeaders = [.defaultAcceptEncoding,
                                             .defaultAcceptLanguage,
                                             .defaultUserAgent]
    }
    

    interceptor

    对于这个参数,我的理解是在请求前及请求失败时候对request做统一处理的地方,首先我们看一下这个协议的定义

    /// Type that provides both `RequestAdapter` and `RequestRetrier` functionality.
    public protocol RequestInterceptor: RequestAdapter, RequestRetrier {}
    
    extension RequestInterceptor {
        public func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (AFResult<URLRequest>) -> Void) {
            completion(.success(urlRequest))
        }
    
        public func retry(
            _ request: Request,
            for session: Session,
            dueTo error: Error,
            completion: @escaping (RetryResult) -> Void)
        {
            completion(.doNotRetry)
        }
    }
    

    第一个方法,会在请求发起之前进行调用,比如我们可以在这个地方对urlRequest进行一些请求参数及请求头的修改;
    第二个方法则会在请求失败后进行调用。(有请求结果,例如response.statusCode = 400之类的不会调用,因为这不算一次失败的请求,当然如果我们想让如此之类的请求也走该回调方便做统一处理,那么我们的请求方法需要这么写 Alamofile.request(url).validate().response。 中间添加一个validate)

    我们看一下validate具体做了什么:
    首先Validation.swift文件中有这么一个参数fileprivate var acceptableStatusCodes: Range<Int> { return 200..<300 },也就是200..<300以外的statusCode会走上边的retry(_request:for:dueTo:completion)方法

    我们看到Validation.swift文件中对DataRequest有如下扩展

    extension DataRequest {
        /// Validates that the response has a status code in the specified sequence.
        ///
        /// If validation fails, subsequent calls to response handlers will have an associated error.
        ///
        /// - parameter range: The range of acceptable status codes.
        ///
        /// - returns: The request.
        @discardableResult
        public func validate<S: Sequence>(statusCode acceptableStatusCodes: S) -> Self where S.Iterator.Element == Int {
            return validate { [unowned self] _, response, _ in
                return self.validate(statusCode: acceptableStatusCodes, response: response)
            }
        }
    }
    

    该方法,调用了Request.swift文件中的方法

    @discardableResult
        public func validate(_ validation: @escaping Validation) -> Self {
            let validator: () -> Void = { [unowned self] in
                guard self.error == nil, let response = self.response else { return }
    
                let result = validation(self.request, response, self.data)
    
                if case .failure(let error) = result { self.error = error }
    
                self.eventMonitor?.request(self,
                                           didValidateRequest: self.request,
                                           response: response,
                                           data: self.data,
                                           withResult: result)
            }
    
            protectedValidators.append(validator)
    
            return self
        }
    

    该方法把block保存在protectedValidators中,当请求结束后,会对请求结果code进行一个比对,如下

    func didCompleteTask(_ task: URLSessionTask, with error: Error?) {
            self.error = self.error ?? error
            // 如果我们请求时调用了 .validate() 则这个数组中便存在对应的 block,进行遍历,会把 200..<300 以外的code算为 Error,然后就会走 retry(_request:for:dueTo:completion) 这个方法
            protectedValidators.directValue.forEach { $0() }
    
            eventMonitor?.request(self, didCompleteTask: task, with: error)
    
            retryOrFinish(error: self.error)
        }
    
        func retryOrFinish(error: Error?) {
            guard let error = error, let delegate = delegate else { finish(); return }
    
            delegate.retryResult(for: self, dueTo: error) { retryResult in
                switch retryResult {
                case .doNotRetry, .doNotRetryWithError:
                    self.finish(error: retryResult.error)
                case .retry, .retryWithDelay:
                    delegate.retryRequest(self, withDelay: retryResult.delay)
                }
            }
        }
    

    上面的protectedValidators.directValue.forEach { $0() }这句代码会走到该方法

    public func validate(_ validation: @escaping Validation) -> Self {
            let validator: () -> Void = { [unowned self] in
                guard self.error == nil, let response = self.response else { return }
    
                let result = validation(self.request, response, self.data)
    
                if case .failure(let error) = result { self.error = error }
    
                self.eventMonitor?.request(self,
                                           didValidateRequest: self.request,
                                           response: response,
                                           data: self.data,
                                           withResult: result)
            }
    
            protectedValidators.append(validator)
    
            return self
        }
    

    这个方法中的let result = validation(self.request, response, self.data)则会对code进行对比

    fileprivate func validate<S: Sequence>(
            statusCode acceptableStatusCodes: S,
            response: HTTPURLResponse)
            -> ValidationResult
            where S.Iterator.Element == Int
        {
            if acceptableStatusCodes.contains(response.statusCode) {
                return .success(Void())
            } else {
                let reason: ErrorReason = .unacceptableStatusCode(code: response.statusCode)
                return .failure(AFError.responseValidationFailed(reason: reason))
            }
        }
    

    相关文章

      网友评论

          本文标题:Alamofire 5.0.0-beta.7 源码阅读(一)

          本文链接:https://www.haomeiwen.com/subject/rlemdctx.html