Alamofire源碼學習(三): Session相關的其餘幾個類

往期導航:

Alamofire源碼學習目錄合集linux

相關文件:

SessionDelegate.swift
EventMonitor.swift
NetworkReachabilityManager.swiftswift

SessionDelegate.swift

  • 聲明瞭類SessionDelegate, 實現URLSessionDelegate以及各個URLSessionTaskDelegate並把各個狀態事件派發給事件監聽器對象:
    • 持有一個FileManager對象, 可以使用自定義對象初始化, 用來處理下載請求的文件操做(刪除已存在文件, 建立目錄)
    • 持有一個弱引用SessionStateProvider協議對象指向Session, 用來從Session保存的Request-Task的映射關係中, 根據Task獲取對應的Request對象
    • 持有一個強引用EventMonitor協議對象, 用來接收請求中的各個狀態事件
    • 只有一個方法:
      //根據Task獲取對應的Request, 並轉換成對應的子類
      func request<R: Request>(for task: URLSessionTask, as type: R.Type) -> R? {
          guard let provider = stateProvider else {
              assertionFailure("StateProvider is nil.")
              return nil
          }
          
          //從SessionStateProvider(Session)中根據task獲取request
          return provider.request(for: task) as? R
      }
      複製代碼
  • 定義協議SessionStateProvider, 鏈接Session跟SessionDelegate(Sesson實現了該協議)
    protocol SessionStateProvider: AnyObject {
        //從Session中獲取證書管理器、重定向管理器、緩存管理器
        var serverTrustManager: ServerTrustManager? { get }
        var redirectHandler: RedirectHandler? { get }
        var cachedResponseHandler: CachedResponseHandler? { get }
        //從Session的RequestTaskMap映射中根據task拿request
        func request(for task: URLSessionTask) -> Request?
        //獲取到任務任務指標後的回調
        func didGatherMetricsForTask(_ task: URLSessionTask)
        //請求完成的回調, 後續可能會繼續去獲取任務指標
        func didCompleteTask(_ task: URLSessionTask, completion: @escaping () -> Void)
        //認證受權處理
        func credential(for task: URLSessionTask, in protectionSpace: URLProtectionSpace) -> URLCredential?
        //Session失效的回調
        func cancelRequestsForSessionInvalidation(with error: Error?)
    }
    複製代碼
  • 四次擴展類SessionDelegate實現對應實現四個URLSessionDelegate及URLSessionTaskDelegate協議, 用來處理Session以及URLSessionTask變化
    // MARK: URLSessionDelegate
    
    extension SessionDelegate: URLSessionDelegate {
        open func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?) {
            //Session不可用時, 通知監聽器, 而後回調Session取消所有請求
            eventMonitor?.urlSession(session, didBecomeInvalidWithError: error)
            stateProvider?.cancelRequestsForSessionInvalidation(with: error)
        }
    }
    
    // MARK: URLSessionTaskDelegate
    
    extension SessionDelegate: URLSessionTaskDelegate {
        //定義元組包裹認證處理方式, 證書, 以及錯誤
        typealias ChallengeEvaluation = (disposition: URLSession.AuthChallengeDisposition, credential: URLCredential?, error: AFError?)
    
        //收到須要驗證證書的回調
        open func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
            //告知事件監聽器
            eventMonitor?.urlSession(session, task: task, didReceive: challenge)
    
            let evaluation: ChallengeEvaluation
            //組裝認證方式, 證書, 錯誤信息
            switch challenge.protectionSpace.authenticationMethod {
            case NSURLAuthenticationMethodServerTrust:
                //HTTPS認證
                evaluation = attemptServerTrustAuthentication(with: challenge)
            case NSURLAuthenticationMethodHTTPBasic, NSURLAuthenticationMethodHTTPDigest, NSURLAuthenticationMethodNTLM,
                 NSURLAuthenticationMethodNegotiate, NSURLAuthenticationMethodClientCertificate:
                //其餘認證方式
                evaluation = attemptCredentialAuthentication(for: challenge, belongingTo: task)
            default:
                evaluation = (.performDefaultHandling, nil, nil)
            }
            //獲取證書失敗的話, 該請求失敗, 傳遞錯誤
            if let error = evaluation.error {
                stateProvider?.request(for: task)?.didFailTask(task, earlyWithError: error)
            }
            //結果回調
            completionHandler(evaluation.disposition, evaluation.credential)
        }
        //處理服務器認證
        func attemptServerTrustAuthentication(with challenge: URLAuthenticationChallenge) -> ChallengeEvaluation {
            let host = challenge.protectionSpace.host
    
            guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
                  let trust = challenge.protectionSpace.serverTrust
            else {
                //若是沒有自定義證書管理器 直接返回默認處理便可
                return (.performDefaultHandling, nil, nil)
            }
    
            do {
                guard let evaluator = try stateProvider?.serverTrustManager?.serverTrustEvaluator(forHost: host) else {
                    return (.performDefaultHandling, nil, nil)
                }
                //從ServerTrustManager中取ServerTrustEvaluating對象, 執行自定義認證
                try evaluator.evaluate(trust, forHost: host)
    
                return (.useCredential, URLCredential(trust: trust), nil)
            } catch {
                //自定義認證出錯的話, 返回取消認證操做 + 錯誤
                return (.cancelAuthenticationChallenge, nil, error.asAFError(or: .serverTrustEvaluationFailed(reason: .customEvaluationFailed(error: error))))
            }
        }
    
        //其餘認證方式
        func attemptCredentialAuthentication(for challenge: URLAuthenticationChallenge, belongingTo task: URLSessionTask) -> ChallengeEvaluation {
            guard challenge.previousFailureCount == 0 else {
                //若是以前認證失敗了 直接跳過本次認證, 開始下一次認證
                return (.rejectProtectionSpace, nil, nil)
            }
    
            guard let credential = stateProvider?.credential(for: task, in: challenge.protectionSpace) else {
                //沒有獲取到認證處理對象, 忽略本次認證
                return (.performDefaultHandling, nil, nil)
            }
    
            return (.useCredential, credential, nil)
        }
    
        //上傳進度
        open func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {
            //通知監聽器
            eventMonitor?.urlSession(session,
                                     task: task,
                                     didSendBodyData: bytesSent,
                                     totalBytesSent: totalBytesSent,
                                     totalBytesExpectedToSend: totalBytesExpectedToSend)
            //拿到Request, 更新上傳進度
            stateProvider?.request(for: task)?.updateUploadProgress(totalBytesSent: totalBytesSent,
                                                                    totalBytesExpectedToSend: totalBytesExpectedToSend)
        }
    
        //上傳請求準備上傳新的body流
        open func urlSession(_ session: URLSession, task: URLSessionTask, needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) {
            //通知監聽器
            eventMonitor?.urlSession(session, taskNeedsNewBodyStream: task)
    
            guard let request = request(for: task, as: UploadRequest.self) else {
                //只有上傳請求會響應這個方法
                assertionFailure("needNewBodyStream did not find UploadRequest.")
                completionHandler(nil)
                return
            }
            //從request中拿到InputStream返回, 只有使用InputStream建立的上傳請求才會返回正確, 不然會拋出錯誤
            completionHandler(request.inputStream())
        }
    
        //重定向
        open func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
            //通知監聽器
            eventMonitor?.urlSession(session, task: task, willPerformHTTPRedirection: response, newRequest: request)
    
            if let redirectHandler = stateProvider?.request(for: task)?.redirectHandler ?? stateProvider?.redirectHandler {
                //先看Request有沒有本身的重定向處理器, 再看Session有沒有全局重定向處理器, 有的話處理下
                redirectHandler.task(task, willBeRedirectedTo: request, for: response, completion: completionHandler)
            } else {
                completionHandler(request)
            }
        }
    
        //獲取請求指標
        open func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) {
            //通知監聽器
            eventMonitor?.urlSession(session, task: task, didFinishCollecting: metrics)
            //通知Request
            stateProvider?.request(for: task)?.didGatherMetrics(metrics)
            //通知Session
            stateProvider?.didGatherMetricsForTask(task)
        }
    
        //請求完成, 後續可能回去獲取網頁指標
        open func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
            //通知監聽器
            eventMonitor?.urlSession(session, task: task, didCompleteWithError: error)
    
            let request = stateProvider?.request(for: task)
            //通知Session請求完成
            stateProvider?.didCompleteTask(task) {
                //回調內容爲 確認請求指標完成後, 通知Request請求完成
                request?.didCompleteTask(task, with: error.map { $0.asAFError(or: .sessionTaskFailed(error: $0)) })
            }
        }
    
        //網絡變動致使的請求等待處理
        @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
        open func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) {
            eventMonitor?.urlSession(session, taskIsWaitingForConnectivity: task)
        }
    }
    
    // MARK: URLSessionDataDelegate
    
    extension SessionDelegate: URLSessionDataDelegate {
    
        //收到響應數據
        open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
            //通知監聽器
            eventMonitor?.urlSession(session, dataTask: dataTask, didReceive: data)
            //只有DataRequest跟DataStreamRequest會收到數據
            if let request = request(for: dataTask, as: DataRequest.self) {
                request.didReceive(data: data)
            } else if let request = request(for: dataTask, as: DataStreamRequest.self) {
                request.didReceive(data: data)
            } else {
                assertionFailure("dataTask did not find DataRequest or DataStreamRequest in didReceive")
                return
            }
        }
    
        //處理是否保存緩存
        open func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse, completionHandler: @escaping (CachedURLResponse?) -> Void) {
            //通知監聽器
            eventMonitor?.urlSession(session, dataTask: dataTask, willCacheResponse: proposedResponse)
    
            if let handler = stateProvider?.request(for: dataTask)?.cachedResponseHandler ?? stateProvider?.cachedResponseHandler {
                //用request的緩存處理器處理緩存
                handler.dataTask(dataTask, willCacheResponse: proposedResponse, completion: completionHandler)
            } else {
                //沒有緩存處理器的話,採用默認邏輯處理緩存
                completionHandler(proposedResponse)
            }
        }
    }
    
    // MARK: URLSessionDownloadDelegate
    
    extension SessionDelegate: URLSessionDownloadDelegate {
        //開始斷點續傳的回調
        open func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
            //通知監聽器
            eventMonitor?.urlSession(session,
                                     downloadTask: downloadTask,
                                     didResumeAtOffset: fileOffset,
                                     expectedTotalBytes: expectedTotalBytes)
            guard let downloadRequest = request(for: downloadTask, as: DownloadRequest.self) else {
                //只有DownloadRequest能處理該協議
                assertionFailure("downloadTask did not find DownloadRequest.")
                return
            }
    
            downloadRequest.updateDownloadProgress(bytesWritten: fileOffset,
                                                   totalBytesExpectedToWrite: expectedTotalBytes)
        }
    
        //更新下載進度
        open func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
            //通知監聽器
            eventMonitor?.urlSession(session,
                                     downloadTask: downloadTask,
                                     didWriteData: bytesWritten,
                                     totalBytesWritten: totalBytesWritten,
                                     totalBytesExpectedToWrite: totalBytesExpectedToWrite)
            guard let downloadRequest = request(for: downloadTask, as: DownloadRequest.self) else {
                assertionFailure("downloadTask did not find DownloadRequest.")
                return
            }
    
            downloadRequest.updateDownloadProgress(bytesWritten: bytesWritten,
                                                   totalBytesExpectedToWrite: totalBytesExpectedToWrite)
        }
    
        //下載完成
        open func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
            //通知監聽器
            eventMonitor?.urlSession(session, downloadTask: downloadTask, didFinishDownloadingTo: location)
    
            guard let request = request(for: downloadTask, as: DownloadRequest.self) else {
                assertionFailure("downloadTask did not find DownloadRequest.")
                return
            }
            //準備轉存文件,定義(轉存目錄,下載options)元組
            let (destination, options): (URL, DownloadRequest.Options)
            if let response = request.response {
                //從request拿到轉存目錄
                (destination, options) = request.destination(location, response)
            } else {
                // If there's no response this is likely a local file download, so generate the temporary URL directly.
                (destination, options) = (DownloadRequest.defaultDestinationURL(location), [])
            }
            //通知監聽器
            eventMonitor?.request(request, didCreateDestinationURL: destination)
    
            do {
                //是否刪除舊文件
                if options.contains(.removePreviousFile), fileManager.fileExists(atPath: destination.path) {
                    try fileManager.removeItem(at: destination)
                }
                //是否建立目錄鏈
                if options.contains(.createIntermediateDirectories) {
                    let directory = destination.deletingLastPathComponent()
                    try fileManager.createDirectory(at: directory, withIntermediateDirectories: true)
                }
                //轉存文件
                try fileManager.moveItem(at: location, to: destination)
                //回調給request
                request.didFinishDownloading(using: downloadTask, with: .success(destination))
            } catch {
                //出錯的話拋出異常
                request.didFinishDownloading(using: downloadTask, with: .failure(.downloadedFileMoveFailed(error: error,
                                                                                                           source: location,
                                                                                                           destination: destination)))
            }
        }
    }
    
    複製代碼

RequestTaskMap.swift

只定義了一個結構體:RequestTaskMap, 用來保存Request對象與URLSessionTask的雙向映射, 該結構體被Session持有,能夠用來快速根據Request找到對應的URLSessionTask, 或者根據URLSessionTask找到對應的Request。api

struct RequestTaskMap {
    //task的狀態, 用來決定是否釋放映射(task是否完成, task是否獲取到請求指標)
    private typealias Events = (completed: Bool, metricsGathered: Bool)
    //task到request
    private var tasksToRequests: [URLSessionTask: Request]
    //request到task
    private var requestsToTasks: [Request: URLSessionTask]
    //task的狀態
    private var taskEvents: [URLSessionTask: Events]
    //全部的request
    var requests: [Request] {
        Array(tasksToRequests.values)
    }
    //初始化 默認三個字典均爲空
    init(tasksToRequests: [URLSessionTask: Request] = [:], requestsToTasks: [Request: URLSessionTask] = [:], taskEvents: [URLSessionTask: (completed: Bool, metricsGathered: Bool)] = [:]) {
        self.tasksToRequests = tasksToRequests
        self.requestsToTasks = requestsToTasks
        self.taskEvents = taskEvents
    }
    //角標存取task
    subscript(_ request: Request) -> URLSessionTask? {
        get { requestsToTasks[request] }
        set {
            guard let newValue = newValue else {
                //若是新值爲空, 表示刪除映射, 檢測下是否存在映射關係, 不存在就報錯
                guard let task = requestsToTasks[request] else {
                    fatalError("RequestTaskMap consistency error: no task corresponding to request found.")
                }

                requestsToTasks.removeValue(forKey: request)
                tasksToRequests.removeValue(forKey: task)
                taskEvents.removeValue(forKey: task)

                return
            }
            //保存新的task
            requestsToTasks[request] = newValue
            tasksToRequests[newValue] = request
            taskEvents[newValue] = (completed: false, metricsGathered: false)
        }
    }
    //角標存取request
    subscript(_ task: URLSessionTask) -> Request? {
        get { tasksToRequests[task] }
        set {
            guard let newValue = newValue else {
                guard let request = tasksToRequests[task] else {
                    fatalError("RequestTaskMap consistency error: no request corresponding to task found.")
                }

                tasksToRequests.removeValue(forKey: task)
                requestsToTasks.removeValue(forKey: request)
                taskEvents.removeValue(forKey: task)

                return
            }

            tasksToRequests[task] = newValue
            requestsToTasks[newValue] = task
            taskEvents[task] = (completed: false, metricsGathered: false)
        }
    }
    //映射個數, 作了兩個字典個數判等
    var count: Int {
        precondition(tasksToRequests.count == requestsToTasks.count,
                     "RequestTaskMap.count invalid, requests.count: \(tasksToRequests.count) != tasks.count: \(requestsToTasks.count)")

        return tasksToRequests.count
    }
    //task狀態個數(映射個數, 並且這個屬性沒有用到)
    var eventCount: Int {
        precondition(taskEvents.count == count, "RequestTaskMap.eventCount invalid, count: \(count) != taskEvents.count: \(taskEvents.count)")

        return taskEvents.count
    }
    //是否爲空
    var isEmpty: Bool {
        precondition(tasksToRequests.isEmpty == requestsToTasks.isEmpty,
                     "RequestTaskMap.isEmpty invalid, requests.isEmpty: \(tasksToRequests.isEmpty) != tasks.isEmpty: \(requestsToTasks.isEmpty)")

        return tasksToRequests.isEmpty
    }
    //task狀態是否爲空(其實就是isEmpty)
    var isEventsEmpty: Bool {
        precondition(taskEvents.isEmpty == isEmpty, "RequestTaskMap.isEventsEmpty invalid, isEmpty: \(isEmpty) != taskEvents.isEmpty: \(taskEvents.isEmpty)")

        return taskEvents.isEmpty
    }
    //在Session收到task獲取到請求指標完成後, 會來判斷下task是否徹底完成(請求完成,且獲取指標完成),並更新taskEvents的狀態 所有完成以後, 會刪除映射關係, Session纔會去執行請求完成的相關回調, 該方法返回的值爲是否刪除了映射關係
    mutating func disassociateIfNecessaryAfterGatheringMetricsForTask(_ task: URLSessionTask) -> Bool {
        guard let events = taskEvents[task] else {
            fatalError("RequestTaskMap consistency error: no events corresponding to task found.")
        }

        switch (events.completed, events.metricsGathered) {
        case (_, true): fatalError("RequestTaskMap consistency error: duplicate metricsGatheredForTask call.")
        case (false, false): taskEvents[task] = (completed: false, metricsGathered: true); return false
        case (true, false): self[task] = nil; return true
        }
    }
    //在Session收到task的didComplete回調以後, 來判斷下task是:1.直接完成,2.接着去獲取請求指標. 並更新狀態, 返回是否刪除映射關係
    mutating func disassociateIfNecessaryAfterCompletingTask(_ task: URLSessionTask) -> Bool {
        guard let events = taskEvents[task] else {
            fatalError("RequestTaskMap consistency error: no events corresponding to task found.")
        }

        switch (events.completed, events.metricsGathered) {
        case (true, _): fatalError("RequestTaskMap consistency error: duplicate completionReceivedForTask call.")
        #if os(Linux)
        ///Linux下請求不會獲取指標, 因此完成以後能夠直接刪除映射
        default: self[task] = nil; return true
        #else
        case (false, false):
            if #available(macOS 10.12, iOS 10, watchOS 7, tvOS 10, *) {
                taskEvents[task] = (completed: true, metricsGathered: false); return false
            } else {
                //watchOS 7如下也不會獲取指標, 因此直接刪除映射並返回true
                self[task] = nil; return true
            }
        case (false, true):
            self[task] = nil; return true
        #endif
        }
    }
}
複製代碼

EventMonitor.swift

  • 聲明EventMonitor接口, 用來監聽請求過程當中的各類狀態, 協議定義了一個回調監聽器的隊列(默認主隊列), 以及一大堆方法。
  • Alamofire中有三個類實現了該接口:
    • AlamofireNotifications類, 用來在不一樣階段發送通知使用
    • CompositeEventMonitor類, 用來組合不一樣的監聽器對象(下方詳解)
    • ClosureEventMonitor類, 持有N多個閉包, 把代理調用轉換爲閉包調用
  • Alamofire中持有情況:
    • SessionDelegate類持有一個CompositeEventMonitor組合監聽器對象: Session在初始化時, 接受一個監聽器數組做爲初始化參數, 而後會把這些監聽器加上AlamofireNotifications監聽器組合成一個CompositeEventMonitor來教給SessionDelegate持有, 在Session的代理方法中, 回調這些監聽器
    • 每一個Request對象也持有一個CompositeEventMonitor: 在Session中初始化Request對象時, 把SessionDelegate持有的組合模擬器傳遞給了建立的Request, 在Request響應狀態時, 回調這些監聽器
  • 方法註解:
    /// 內部代理, 對應URLSession的各個代理以及幾個taskdelegate的代理, 還有幾個專門針對Request及其子類的請求週期的代理方法
    public protocol EventMonitor {
        /// 監聽器回調隊列, 默認主隊列
        var queue: DispatchQueue { get }
    
        // MARK: - URLSession事件及幾個TaskDelegate相關事件
    
        // MARK: URLSessionDelegate Events
    
        /// Event called during `URLSessionDelegate`'s `urlSession(_:didBecomeInvalidWithError:)` method.
        func urlSession(_ session: URLSession, didBecomeInvalidWithError error: Error?)
    
        // MARK: URLSessionTaskDelegate Events
    
        /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didReceive:completionHandler:)` method.
        func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge)
    
        /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:)` method.
        func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64)
    
        /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:needNewBodyStream:)` method.
        func urlSession(_ session: URLSession, taskNeedsNewBodyStream task: URLSessionTask)
    
        /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)` method.
        func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest)
    
        /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didFinishCollecting:)` method.
        func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics)
    
        /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:task:didCompleteWithError:)` method.
        func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
    
        /// Event called during `URLSessionTaskDelegate`'s `urlSession(_:taskIsWaitingForConnectivity:)` method.
        @available(macOS 10.13, iOS 11.0, tvOS 11.0, watchOS 4.0, *)
        func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask)
    
        // MARK: URLSessionDataDelegate Events
    
        /// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:didReceive:)` method.
        func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)
    
        /// Event called during `URLSessionDataDelegate`'s `urlSession(_:dataTask:willCacheResponse:completionHandler:)` method.
        func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, willCacheResponse proposedResponse: CachedURLResponse)
    
        // MARK: URLSessionDownloadDelegate Events
    
        /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didResumeAtOffset:expectedTotalBytes:)` method.
        func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64)
    
        /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:)` method.
        func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
    
        /// Event called during `URLSessionDownloadDelegate`'s `urlSession(_:downloadTask:didFinishDownloadingTo:)` method.
        func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
    
        // MARK: - Request 及其子類的相關請求週期事件
    
        /// 原始URLRequest成功回調, 若是request有適配器,接下來會使用適配器處理原始URLRequest, 沒有適配器的話,直接回調建立Request方法
        func request(_ request: Request, didCreateInitialURLRequest urlRequest: URLRequest)
    
        /// 建立原始URLRequest失敗回調
        func request(_ request: Request, didFailToCreateURLRequestWithError error: AFError)
    
        /// 建立Request時,適配器對URLRequest成功處理後回調
        func request(_ request: Request, didAdaptInitialRequest initialRequest: URLRequest, to adaptedRequest: URLRequest)
    
        /// 適配器處理Request失敗
        func request(_ request: Request, didFailToAdaptURLRequest initialRequest: URLRequest, withError error: AFError)
    
        /// 建立Request成功(在適配器處理後)
        func request(_ request: Request, didCreateURLRequest urlRequest: URLRequest)
    
        /// 建立URLSessionTask成功
        func request(_ request: Request, didCreateTask task: URLSessionTask)
    
        /// 收到請求指標回調
        func request(_ request: Request, didGatherMetrics metrics: URLSessionTaskMetrics)
    
        /// 由Alamofire建立拋出的錯誤, 好比自定義認證處理失敗
        func request(_ request: Request, didFailTask task: URLSessionTask, earlyWithError error: AFError)
    
        ///URLSessionTask請求完成,可能成功可能失敗,接下來會斷定是否須要重試,若是會重試,該回調會被調用屢次
        func request(_ request: Request, didCompleteTask task: URLSessionTask, with error: AFError?)
    
        /// 準備開始重試
        func requestIsRetrying(_ request: Request)
    
        /// 請求完成,開始解析響應數據
        func requestDidFinish(_ request: Request)
    
        //接下來的6個方法都爲主動調用Request,而後影響到關聯的Task時的回調,成對出現
    
        /// Request調用resume方法的時候會回調該方法
        func requestDidResume(_ request: Request)
    
        /// Request關聯的URLSessionTask繼續的時候回調
        func request(_ request: Request, didResumeTask task: URLSessionTask)
    
        /// Request調用suspend掛起
        func requestDidSuspend(_ request: Request)
    
        /// Request關聯的Task被掛起
        func request(_ request: Request, didSuspendTask task: URLSessionTask)
    
        /// Request調用cancel
        func requestDidCancel(_ request: Request)
    
        ///Request關聯的Task被取消
        func request(_ request: Request, didCancelTask task: URLSessionTask)
    
        // MARK: DataRequest 特有事件
    
        /// 檢測響應是否有效成功後回調
        func request(_ request: DataRequest, didValidateRequest urlRequest: URLRequest?, response: HTTPURLResponse, data: Data?, withResult result: Request.ValidationResult)
    
        /// DataRequest成功建立Data類型的DataResponse時回調(沒有序列化)
        func request(_ request: DataRequest, didParseResponse response: DataResponse<Data?, AFError>)
    
        /// DataRequest成功建立序列化的DataResponse時回調
        func request<Value>(_ request: DataRequest, didParseResponse response: DataResponse<Value, AFError>)
    
        // MARK: DataStreamRequest 特有事件
    
        ///檢測響應有效成功
        func request(_ request: DataStreamRequest, didValidateRequest urlRequest: URLRequest?, response: HTTPURLResponse, withResult result: Request.ValidationResult)
    
        /// 從stream中成功序列化數據後調用
        func request<Value>(_ request: DataStreamRequest, didParseStream result: Result<Value, AFError>)
    
        // MARK: UploadRequest 特有事件
    
        /// 上傳請求成功建立Uploadable協議對象成功
        func request(_ request: UploadRequest, didCreateUploadable uploadable: UploadRequest.Uploadable)
    
        /// 上傳請求建立Uploadable失敗
        func request(_ request: UploadRequest, didFailToCreateUploadableWithError error: AFError)
    
        /// 當上傳請求從InputSteam開始提供數據時回調, 只有在上傳請求的InputStream不是Data也不是文件url類型纔會回調
        func request(_ request: UploadRequest, didProvideInputStream stream: InputStream)
    
        // MARK: DownloadRequest 特有事件
    
        /// 下載Task完成,且緩存文件被清除以後回調
        func request(_ request: DownloadRequest, didFinishDownloadingUsing task: URLSessionTask, with result: Result<URL, AFError>)
    
        /// 下載請求成功建立轉存目錄後回調
        func request(_ request: DownloadRequest, didCreateDestinationURL url: URL)
    
        /// 下載請求檢測有效性成功
        func request(_ request: DownloadRequest, didValidateRequest urlRequest: URLRequest?, response: HTTPURLResponse, fileURL: URL?, withResult result: Request.ValidationResult)
    
        /// 使用原數據解析響應成功(沒有序列化)
        func request(_ request: DownloadRequest, didParseResponse response: DownloadResponse<URL?, AFError>)
    
        ///序列化解析響應成功
        func request<Value>(_ request: DownloadRequest, didParseResponse response: DownloadResponse<Value, AFError>)
    }
    複製代碼
  • 聲明接口後, 擴展了接口, 對全部的方法添加了空實現, 對隊列返回默認主隊列。若是要本身實現監聽器, 只用實現本身感興趣的接口便可。
  • CompositeEventMonitor組合監聽器類:
    • queue爲一個異步隊列//TODO
    • 以監聽器數組初始化, 持有這些數組
    • 定義了一個performEvent方法用來派發回調
    func performEvent(_ event: @escaping (EventMonitor) -> Void) {
        //在本身的隊列中,異步循環, 在每一個監聽器各自的隊列回調方法
        queue.async {
            for monitor in self.monitors {
                monitor.queue.async { event(monitor) }
            }
        }
    }
    複製代碼
  • ClosureEventMonitor閉包監聽器類:
    • queue爲主隊列
    • 持有N個可選閉包,N爲EventMonitor接口的方法數, 每一個閉包對應一個接口, 閉包的出入參與接口的出入參對應
    • 每一個協議的實現都爲調用對應的閉包

NetworkReachabilityManager.swift

  • 網絡狀態監聽管理器, watchos與linux不可用
  • 核心爲SystemConfiguration系統模塊
  • 定義網絡狀態枚舉NetworkReachabilityStatus
    • 未知
    • 無網絡
    • 聯網(子狀態ConnectionType):
      • 以太網/wifi
      • 移動網絡
  • 定義別名Listener,其實是一個閉包:(話說swift很多第三方庫都給閉包定義一個別名, 當作對象用, 函數是一等公民)
    public typealias Listener = (NetworkReachabilityStatus) -> Void
  • 定義了幾個快速判斷網絡的只讀計算屬性
  • 持有一個reachabilityQueue的隊列, 用來監聽網絡變化
  • 定義了一個MutableState結構體, 持有一個Listener對象, 一個listener回調的隊列, 一箇舊的網絡狀態
  • 持有一個線程安全的MutableState變量, 網絡變化時,在listener回調隊列中, 通知listener。

純屬我的理解, 可能存在理解錯誤的地方, 若有錯誤, 歡迎評論指出~ 感謝~數組

相關文章
相關標籤/搜索