美文网首页
Alamofire中SessionManager之DataReq

Alamofire中SessionManager之DataReq

作者: Emma_虫儿 | 来源:发表于2019-08-20 17:12 被阅读0次

    你好,我是Emma,今天研究的课题是Alamofire中SessionManager和DataRequest以及task之间的关系。本篇文档以SessionManager.default.request(urlString)
    .response { (response) in debugPrint(response) }为切入点。

    1. SessionManager类

    open class SessionManager {
        public static let `default`: SessionManager = {
            let configuration = URLSessionConfiguration.default
            configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
    
            return SessionManager(configuration: configuration)
        }()
    }
    

    其中的SessionManager.defaultHTTPHeaders指的是什么?

    public static let defaultHTTPHeaders: HTTPHeaders = {
            let acceptEncoding: String = "gzip;q=1.0, compress;q=0.5"
            
            let acceptLanguage = Locale.preferredLanguages.prefix(6).enumerated().map { index, languageCode in
                let quality = 1.0 - (Double(index) * 0.1)
                return "\(languageCode);q=\(quality)"
            }.joined(separator: ", ")
    
            let userAgent: String = {...}()
            return [
                "Accept-Encoding": acceptEncoding,
                "Accept-Language": acceptLanguage,
                "User-Agent": userAgent
            ]
        }()
    

    初始化方法:

    open class SessionManager {
        public init(
            configuration: URLSessionConfiguration = URLSessionConfiguration.default,
            //原生和Alomofire之间的代理移交
            delegate: SessionDelegate = SessionDelegate(),
            serverTrustPolicyManager: ServerTrustPolicyManager? = nil)
        {
            //设置代理这个类的delegate 就是 SessionDelegate = SessionDelegate(),做的是移交工作。
            //这里是如何实现将UIApplicationDelegate后台的方法桥接到URLSessionDelegate中的初始化方法。这点体现了SessionDelegate这个类的强大之处。
            self.delegate = delegate
            //初始化这个类的URLSession
            self.session = URLSession(configuration: configuration, delegate: delegate, delegateQueue: nil)
            //提供给SessionDelegate的一些变量初始化
            commonInit(serverTrustPolicyManager: serverTrustPolicyManager)
        }
    }
    

    commonInit方法的具体实现:

    //好吧,被SessionDelegate 的set方法附身之感
    private func commonInit(serverTrustPolicyManager: ServerTrustPolicyManager?) {
        session.serverTrustPolicyManager = serverTrustPolicyManager
    //初始化中有self.delegate = delegate,这里有delegate.sessionManager持有self不会造成循环引用吗?不会。原因 `weak var sessionManager: SessionManager?`
        delegate.sessionManager = self
    
    //这个主要是给这个类提供backgroundCompletionHandler?()属性的作用。
    delegate.sessionDidFinishEventsForBackgroundURLSession = { [weak self] session in
            guard let strongSelf = self else { return }
            DispatchQueue.main.async { strongSelf.backgroundCompletionHandler?() }
        }
    }
    

    SessionManager与SessionDelegate的关联小节:

    open class SessionManager {
        public let delegate: SessionDelegate 
        public init?(delegate: SessionDelegate)
        {
            self.delegate = delegate
            commonInit()
        }
        private func commonInit() {
            delegate.sessionManager = self
        }
    }
    open class SessionDelegate: NSObject {
        weak var sessionManager: SessionManager?
    }
    //这样双方互相持有但是是打破循环链的持有。可以在SessionDelegate中做一些关于SessionManager的容错处理。
    

    2.Request之DataRequest

    下面进入今天的正题Request之DataRequest,首先看request方法:

    @discardableResult
    open func request(
        _ url: URLConvertible,
        method: HTTPMethod = .get,//指定是请求的方法类型
        parameters: Parameters? = nil,//参数
        encoding: ParameterEncoding = URLEncoding.default,//编码,此处默认的是URLEncoding.default
        headers: HTTPHeaders? = nil)
        -> DataRequest
    {
        var originalRequest: URLRequest?
    
        do {
            originalRequest = try URLRequest(url: url, method: method, headers: headers)
            //重点重点,编码重点
            let encodedURLRequest = try encoding.encode(originalRequest!, with: parameters)
            return request(encodedURLRequest)
        } catch {
            return request(originalRequest, failedWith: error)
        }
    }
    

    方法的百分号编码和区分方法的具体实现:

    public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
        var urlRequest = try urlRequest.asURLRequest()
    //判断是否有参数
        guard let parameters = parameters else { return urlRequest }
    //根据HTTPMethod这个枚举进行派分
        if let method = HTTPMethod(rawValue: urlRequest.httpMethod ?? "GET"), encodesParametersInURL(with: method) {
            guard let url = urlRequest.url else {
                throw AFError.parameterEncodingFailed(reason: .missingURL)
            }
    
            if var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false), !parameters.isEmpty {
            //进行百分号编码和添加&符号。
                let percentEncodedQuery = (urlComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
                urlComponents.percentEncodedQuery = percentEncodedQuery
                urlRequest.url = urlComponents.url
            }
        } else {
            if urlRequest.value(forHTTPHeaderField: "Content-Type") == nil {
                urlRequest.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
            }
    
            urlRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
        }
    
        return urlRequest
    }
    
    
    private func query(_ parameters: [String: Any]) -> String {
        //创建元祖
        var components: [(String, String)] = []
        //遍历
        for key in parameters.keys.sorted(by: <) {
            let value = parameters[key]!
            //进行递归操作去除key,value
            components += queryComponents(fromKey: key, value: value)
        }
        //joined添加&分隔符,实例:A&B&C
        return components.map { "\($0)=\($1)" }.joined(separator: "&")
        
    }
    

    从request方法闭包中的return request(encodedURLRequest)方法可以看出走的是下面这步

    @discardableResult
    open func request(_ urlRequest: URLRequestConvertible) -> DataRequest {
        var originalRequest: URLRequest?
        do {
        //保存的请求
            originalRequest = try urlRequest.asURLRequest()
        //保存的任务
            let originalTask = DataRequest.Requestable(urlRequest: originalRequest!)
    
            let task = try originalTask.task(session: session, adapter: adapter, queue: queue)
            //重点点击进入下面代码,RequestTask是枚举,区分了.data,.download,.stream,.upload
            let request = DataRequest(session: session, requestTask: .data(originalTask, task))
            //task和Request是意义对应的关联关系。
            delegate[task] = request
            if startRequestsImmediately { request.resume() }
            return request
        } catch {
            return request(originalRequest, failedWith: error)
        }
    }
    
    //保存了DataRequest的task适配器请求序列
    struct Requestable: TaskConvertible {
        let urlRequest: URLRequest
        func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
            do {
                let urlRequest = try self.urlRequest.adapt(using: adapter)
                //重点是通过请求找到dataTask
                return queue.sync { session.dataTask(with: urlRequest) }
            } catch {
                throw AdaptError(error: error)
            }
        }
    }
    

    这个Request的初始化主要是一些与task的代理之间的持有关系和保存一些值。

    open class Request{
        init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
        //session这是是用来进行保存session的。
            self.session = session
        //  requestTask是一个枚举,进行任务和代理的分发
            switch requestTask {
            case .data(let originalTask, let task):
                taskDelegate = DataTaskDelegate(task: task)
                self.originalTask = originalTask
            case .download(let originalTask, let task):
                taskDelegate = DownloadTaskDelegate(task: task)
                self.originalTask = originalTask
            case .upload(let originalTask, let task):
                taskDelegate = UploadTaskDelegate(task: task)
                self.originalTask = originalTask
            case .stream(let originalTask, let task):
                taskDelegate = TaskDelegate(task: task)
                self.originalTask = originalTask
            }
        
            delegate.error = error
            //此处这个线程添加了addOperation ,其初始化见下面代码。
            delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
        }
    }
    
    open class TaskDelegate: NSObject {
        init(task: URLSessionTask?) {
        //关于task代理中线程的初始化
            self.queue = {
                let operationQueue = OperationQueue() 
                operationQueue.maxConcurrentOperationCount = 1
                operationQueue.isSuspended = true
                operationQueue.qualityOfService = .utility
                return operationQueue
            }()
        }
    }
    

    总结:

    1)delegate[task] = request这样设计的原因是什么?

    原因是实现SessionManager和Request之间的解耦。

    2)那么SessionManager,Request,Task之间各自负责什么职能又是如何联系的?

    SessionManager通过SessionDelegate来做请求的主体序列,通过这个来塞入一些头信息。请求体就有DataRequest等Request来负责,他负责的是一些URL,params,Method,Ecode,header等的打包,请求得开线程啊,线程这部分就分离出来由task负责,并且是Request和task是一对一的对练关系。

    相关文章

      网友评论

          本文标题:Alamofire中SessionManager之DataReq

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