【Alamofire源码解析】11 - TaskDelegate

这个文件定义了几个delegate类型。TaskDelegateDataTaskDelegateDownloadTaskDelegate的父类;其中DataTaskDelegateUploadTaskDelegate的父类。

1. TaskDelegate

SessionDelegate类似,TaskDelegate用于处理task的所有回调和执行队列的operations。

1) 属性和初始化方法

// 任务完成后,执行这个队列里的所有operations
open let queue: OperationQueue

// 服务器返回的数据,这里返回nil,然后让子类去重写
public var data: Data? { return nil }

// 整个任务过程中出现的错误
public var error: Error?

// 作者为了在get和set的时候加锁,定义了一个私有的_task
var task: URLSessionTask? {
    set {
        taskLock.lock(); defer { taskLock.unlock() }
        _task = newValue
    }
    get {
        taskLock.lock(); defer { taskLock.unlock() }
        return _task
    }
}

var initialResponseTime: CFAbsoluteTime? // 服务器最开始响应的时间
var credential: URLCredential? // URL证书
var metrics: AnyObject? // URLSessionTaskMetrics

private var _task: URLSessionTask? {
    didSet { reset() }
}

private let taskLock = NSLock()

init(task: URLSessionTask?) {
    _task = task

    // 这里利用了一个closure来初始化queue
    // 我们可以学习这种模式,可以让代码看起来更清晰
    self.queue = {
        let operationQueue = OperationQueue()

        operationQueue.maxConcurrentOperationCount = 1
        // 刚初始化,把这个属性设置为true暂时不执行队列里面的operation
        operationQueue.isSuspended = true
        operationQueue.qualityOfService = .utility

        return operationQueue
    }()
}

func reset() {
    error = nil
    initialResponseTime = nil
}

2) 实现URLSessionTaskDelegate

// 定义了与回调对应的closure
var taskWillPerformHTTPRedirection: ((URLSession, URLSessionTask, HTTPURLResponse, URLRequest) -> URLRequest?)?
var taskDidReceiveChallenge: ((URLSession, URLSessionTask, URLAuthenticationChallenge) -> (URLSession.AuthChallengeDisposition, URLCredential?))?
var taskNeedNewBodyStream: ((URLSession, URLSessionTask) -> InputStream?)?
var taskDidCompleteWithError: ((URLSession, URLSessionTask, Error?) -> Void)?

// 告诉代理服务器请求HTTP重定向
// @objc的意思是告诉在OC使用的时候如何显示这个方法
@objc(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)
func urlSession(
    _ session: URLSession,
    task: URLSessionTask,
    willPerformHTTPRedirection response: HTTPURLResponse,
    newRequest request: URLRequest,
    completionHandler: @escaping (URLRequest?) -> Void)
{
    var redirectRequest: URLRequest? = request

    // 如果提供了taskWillPerformHTTPRedirection,则更新redirectRequest
    if let taskWillPerformHTTPRedirection = taskWillPerformHTTPRedirection {
        redirectRequest = taskWillPerformHTTPRedirection(session, task, response, request)
    }

    completionHandler(redirectRequest)
}

// 服务器请求认证
@objc(URLSession:task:didReceiveChallenge:completionHandler:)
func urlSession(
    _ session: URLSession,
    task: URLSessionTask,
    didReceive challenge: URLAuthenticationChallenge,
    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
    // 初始化一个默认的配置,就像客户端没有实现这个回调
    var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
    var credential: URLCredential?

    if let taskDidReceiveChallenge = taskDidReceiveChallenge {
        // 如果taskDidReceiveChallenge,更新disposition和credential
        (disposition, credential) = taskDidReceiveChallenge(session, task, challenge)
    } else if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust { // 认证方法是ServerTrust
        
        // 获取保护区域的主机地址
        let host = challenge.protectionSpace.host

        // 判断我们是否提供了服务器信任策略
        if let serverTrustPolicy = session.serverTrustPolicyManager?.serverTrustPolicy(forHost: host),
            let serverTrust = challenge.protectionSpace.serverTrust
        {
            // 评估serverTrust对这个主机地址是否有效
            if serverTrustPolicy.evaluate(serverTrust, forHost: host) {
                // 评估通过,把disposition更新为使用证书;并更新证书
                disposition = .useCredential
                credential = URLCredential(trust: serverTrust)
            } else {
                // 评估不通过,取消认证,整个请求也会被取消
                disposition = .cancelAuthenticationChallenge
            }
        }
    } else {
        if challenge.previousFailureCount > 0 { // 之前认证失败的次数大于0
            // 更新disposition为rejectProtectionSpace,当前这个challenge被拒绝
            disposition = .rejectProtectionSpace
        } else { // 之前认证失败的次数不大于0
            
            // 使用证书进行认证
            credential = self.credential ?? session.configuration.urlCredentialStorage?.defaultCredential(for: challenge.protectionSpace)

            if credential != nil {
                disposition = .useCredential
            }
        }
    }

    // 最后执行completionHandler
    completionHandler(disposition, credential)
}

// 服务器请求新的inputStream
@objc(URLSession:task:needNewBodyStream:)
func urlSession(
    _ session: URLSession,
    task: URLSessionTask,
    needNewBodyStream completionHandler: @escaping (InputStream?) -> Void)
{
    var bodyStream: InputStream?

    if let taskNeedNewBodyStream = taskNeedNewBodyStream {
        bodyStream = taskNeedNewBodyStream(session, task)
    }

    completionHandler(bodyStream)
}

// 任务完成
@objc(URLSession:task:didCompleteWithError:)
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    // 如果有taskDidCompleteWithError,则执行
    if let taskDidCompleteWithError = taskDidCompleteWithError {
        taskDidCompleteWithError(session, task, error)
    } else { // 没有taskDidCompleteWithError
        if let error = error {
            
            // 设置error
            if self.error == nil { self.error = error }

            // 如果error不为空的话,userInfo里面携带有resumeData
            if let downloadDelegate = self as? DownloadTaskDelegate,
                let resumeData = (error as NSError).userInfo[NSURLSessionDownloadTaskResumeData] as? Data
            {
                downloadDelegate.resumeData = resumeData
            }
        }
        
        // 执行队列里的所有operations
        queue.isSuspended = false
    }
}

2. DataTaskDelegate

1) 属性和初始化方法

var dataTask: URLSessionDataTask { return task as! URLSessionDataTask }

// 重写父类的属性,服务器返回的数据
override var data: Data? {
    if dataStream != nil { // 如果有dataStream去处理data,这里的data就返回nil
        return nil
    } else {
        return mutableData // 返回从服务器接收到的数据
    }
}

var progress: Progress // 进度
var progressHandler: (closure: Request.ProgressHandler, queue: DispatchQueue)?

var dataStream: ((_ data: Data) -> Void)? // 处理数据的closure

private var totalBytesReceived: Int64 = 0
private var mutableData: Data // 用于存储从服务器接收到的数据

private var expectedContentLength: Int64? // 服务器文件的总大小

override init(task: URLSessionTask?) {
    mutableData = Data()
    progress = Progress(totalUnitCount: 0)

    super.init(task: task)
}

override func reset() {
    super.reset()

    progress = Progress(totalUnitCount: 0)
    totalBytesReceived = 0
    mutableData = Data()
    expectedContentLength = nil
}

3. DownloadTaskDelegate & UploadTaskDelegate

这两个delegate与DataTaskDelegate非常类似,大家可以自己看下,如果有不懂的,欢迎留言,我会尽力解答。

有任何问题,欢迎大家留言!

欢迎加入我管理的Swift开发群:536353151,本群只讨论Swift相关内容。

原创文章,转载请注明出处。谢谢!

你可能感兴趣的:(【Alamofire源码解析】11 - TaskDelegate)