美文网首页
Alamofire-request

Alamofire-request

作者: Code_人生 | 来源:发表于2019-08-23 14:27 被阅读0次
    一、SessionManager的总结
    • SessionManager 就是对外提供的管理者,这个管理者具备整个 Alamofire 的所有功能。
      • 其中一个非常重要的点就是SessionManagerSession的代理移交给了一个专门的类 : SessionDelegate
    • 从上面这张图可以看出,我们的对外模块是SessionManager,他给外界的用户提供了很多的功能
    • 但是这些工作的真正实现者是由iOS、Android、前端、后台、测试实现的!
    • 其中单拿 iOS 模块的任务来说,有 首页、发现、我的、SDK、视频....模块要实现,但是我们的项目经理有可能都不知道这些到底是什么,怎么实现!所有来说如果全部交给SessionManager来实现,显然耦合性过强,还有任务乱七八糟,没有体现一个牛逼项目分层架构的效果。所以在 iOS 任务细化和SessionManager之间就缺了一个小管理者,对下:他知道具体事务和调度。对上:他能和SessionManager协调配合。那就是Request
    二、Request初探
            SessionManager.default.request(urlString, method: .post, parameters: ["username":"dyz"]).response { (response) in
                debugPrint(response)
            }
    
    • 1、method 分析 - options、get、head、post、put、patch、delete、trace、connect
      get:参数拼接到url
      post:参数放到了httpBody
    • 2、url -> URLRequest -> 创建Task
    • 3、parameters:参数处理
        @discardableResult
        open func request(
            _ url: URLConvertible,
            method: HTTPMethod = .get,
            parameters: Parameters? = nil,
            encoding: ParameterEncoding = 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)
            }
        }
    
    • originalRequest = try URLRequest(url: url, method: method, headers: headers) 根据url、method和headers创建一个URLRequest
    • encoding.encode(originalRequest!, with: parameters) 编码,返回编码之后的URLRequest
        public func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
            var urlRequest = try urlRequest.asURLRequest()
    
            guard let parameters = parameters else { return urlRequest }
    
            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
        }
    
    • encodesParametersInURL(with: method) 区分参数是拼接在url上,还是放在httpBody中
    • query(parameters) 参数处理
    • urlComponents.percentEncodedQuery = percentEncodedQuery 百分号编码,默认是ASCII码。"username=%E9%82%93%E4%BA%9A%E6%B4%B2dyz" 百分号解码网址
        private func query(_ parameters: [String: Any]) -> String {
            var components: [(String, String)] = []
    
            for key in parameters.keys.sorted(by: <) {
                let value = parameters[key]!
                components += queryComponents(fromKey: key, value: value)
            }
            return components.map { "\($0)=\($1)" }.joined(separator: "&")
        }
    
    • queryComponents(fromKey: key, value: value) 递归,返回一个数组,数组里面放的是元组
        public func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
            var components: [(String, String)] = []
    
            if let dictionary = value as? [String: Any] {
                for (nestedKey, value) in dictionary {
                    components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
                }
            } else if let array = value as? [Any] {
                for value in array {
                    components += queryComponents(fromKey: arrayEncoding.encode(key: key), value: value)
                }
            } else if let value = value as? NSNumber {
                if value.isBool {
                    components.append((escape(key), escape(boolEncoding.encode(value: value.boolValue))))
                } else {
                    components.append((escape(key), escape("\(value)")))
                }
            } else if let bool = value as? Bool {
                components.append((escape(key), escape(boolEncoding.encode(value: bool))))
            } else {
                components.append((escape(key), escape("\(value)")))
            }
    
            return components
        }
    
    • 根据不同的数据类型,进行处理
    • escape 里面对参数进行百分号编码
    三、Request-参数传递坑点
    • joined 在中间插入字符
            let arr = ["hello","world","dyz","和谐学习,不急不躁"]
            let comArr = arr.map{$0}.joined(separator: "&")
            print(comArr)
    
    hello&world&dyz&和谐学习,不急不躁
    
    • 参数里面有数组的时候,要把数组JSON序列化
            let array = [["username":"dyz","password":"123456"],["username":"Json","password":"9080"]]
            SessionManager.default.request(myGetUrlString, method: .get, parameters: ["array":getJsonFromArray(array)])
                .response { (response) in
                    debugPrint(response)
            }
    
    extension ViewController {
        fileprivate func getJsonFromArray(_ array:Array<Any>) -> String{
            let data = try? JSONSerialization.data(withJSONObject: array, options: .prettyPrinted)
            return String(data: data!, encoding: .utf8) ?? ""
        }
    }
    
    四、SessionDelegate和TaskDelegate的关系

    SessionDelegate 是事件总响应者,根据不同的需求 (DataTaskDelegateDownloadTaskDelegateUploadTaskDelegateTaskDelegate),响应总代理然后根据需求的不同交给专业的人去做专业的事

    代理任务下发的两种情况?

    • 1:用户提供方案 else 系统默认
    • 2:用户可以监听,但是还有一些任务用户做不了,我们还是要做
        @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)
                let request = DataRequest(session: session, requestTask: .data(originalTask, task))
    
                delegate[task] = request
    
                if startRequestsImmediately { request.resume() }
    
                return request
            } catch {
                return request(originalRequest, failedWith: error)
            }
        }
    
    • delegate[task] = request requesttask(URLSessionTask)绑定在一起,SessionDelegate下标法
    • Requestable 结构体 相当与一个助理的身份,实现TaskConvertible协议的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)
                    return queue.sync { session.dataTask(with: urlRequest) }
                } catch {
                    throw AdaptError(error: error)
                }
            }
        }
    
    • task方法,返回一个URLSessionTask
    • DataRequest初始化方法
        init(session: URLSession, requestTask: RequestTask, error: Error? = nil) {
            self.session = session
    
            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
            delegate.queue.addOperation { self.endTime = CFAbsoluteTimeGetCurrent() }
        }
    
    • taskDelegate = DataTaskDelegate(task: task)
    • DataTaskDelegate初始化方法
        override init(task: URLSessionTask?) {
            mutableData = Data()
            progress = Progress(totalUnitCount: 0)
    
            super.init(task: task)
        }
    
    • TaskDelegate初始化方法
        init(task: URLSessionTask?) {
            _task = task
    
            self.queue = {
                let operationQueue = OperationQueue()
    
                operationQueue.maxConcurrentOperationCount = 1
                operationQueue.isSuspended = true
                operationQueue.qualityOfService = .utility
    
                return operationQueue
            }()
        }
    
    • SessionDelegate下标法
        open subscript(task: URLSessionTask) -> Request? {
            get {
                lock.lock() ; defer { lock.unlock() }
                return requests[task.taskIdentifier]
            }
            set {
                lock.lock() ; defer { lock.unlock() }
                requests[task.taskIdentifier] = newValue
            }
        }
    
    五、Charles 演示get 和 post
    • get
    • post

    相关文章

      网友评论

          本文标题:Alamofire-request

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