Request.swift
代码结构主要是由Request
及其它的三个子类DataRequest
,DownloadRequest
,UploadRequest
组成,另外还有StreamRequest
这个类很简单文中就没有提及。
-
Request
负责发送请求和接收响应,服务器返回的相关数据,以及管理其URLSessionTas
。
Request
- 阅读这段代码注意最重要的私有属性
taskDelegate
,以及它对应的open
属性delegate
。Request
的操作都是调用对应taskDelegate
中的resume()
,suspend()
,cancel()
方法。
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() }
}·
初始化的时候需要传入URLSession
,RequestTask
,通过不同的requestTask
生成不同的TaskDelegate
赋值给属性taskDelegate。这么做的原因是子类都是调用这个方法初始化,所以不同的子类传入的requestTask
就不同。统一的操作是把originalTask
保存了下来,这么做的目的是当请求失败后再次请求时通过originalTask
的task
方法生成新的URLSessionTask
。
-
Request
的子类都定义了一个实现TaskConvertible
协议的类型,用做初始化自己时使用的RequestTask
参数、
DataRequest
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.syncResult { session.dataTask(with: urlRequest) }
} catch {
throw AdaptError(error: error)
}
}
}
- 定义
TaskConvertible
, 通过task()
返回URLSessionTask
- 重写了
request
属性,在通过父类get
方法没有返回值的情况下放回requestable.urlRequest
-
progress
属性用于表示请求进度 -
var dataDelegate: DataTaskDelegate { return delegate as! DataTaskDelegate }
把父类的TaskDelegate转化成DataTaskDelegate
DownloadRequest
两种下载方式,createIntermediateDirectories
创建中间目录,removePreviousFile
删除目的地之前文件
public struct DownloadOptions: OptionSet {
/// Returns the raw bitmask value of the option and satisfies the `RawRepresentable` protocol.
public let rawValue: UInt
/// A `DownloadOptions` flag that creates intermediate directories for the destination URL if specified.
public static let createIntermediateDirectories = DownloadOptions(rawValue: 1 << 0)
/// A `DownloadOptions` flag that removes a previous file from the destination URL if specified.
public static let removePreviousFile = DownloadOptions(rawValue: 1 << 1)
/// Creates a `DownloadFileDestinationOptions` instance with the specified raw value.
///
/// - parameter rawValue: The raw bitmask value for the option.
///
/// - returns: A new log level instance.
public init(rawValue: UInt) {
self.rawValue = rawValue
}
}
两种下载方式,URLRequest
,Data
可以继续上次未完成的下载任务。
enum Downloadable: TaskConvertible {
case request(URLRequest)
case resumeData(Data)
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
do {
let task: URLSessionTask
switch self {
case let .request(urlRequest):
let urlRequest = try urlRequest.adapt(using: adapter)
task = queue.syncResult { session.downloadTask(with: urlRequest) }
case let .resumeData(resumeData):
task = queue.syncResult { session.downloadTask(withResumeData: resumeData) }
}
return task
} catch {
throw AdaptError(error: error)
}
}
}
- 重写
request
属性 -
resumeData
下载的data
UploadRequest
定义了三种上传的方式
enum Uploadable: TaskConvertible {
case data(Data, URLRequest)
case file(URL, URLRequest)
case stream(InputStream, URLRequest)
func task(session: URLSession, adapter: RequestAdapter?, queue: DispatchQueue) throws -> URLSessionTask {
do {
let task: URLSessionTask
switch self {
case let .data(data, urlRequest):
let urlRequest = try urlRequest.adapt(using: adapter)
task = queue.syncResult { session.uploadTask(with: urlRequest, from: data) }
case let .file(url, urlRequest):
let urlRequest = try urlRequest.adapt(using: adapter)
task = queue.syncResult { session.uploadTask(with: urlRequest, fromFile: url) }
case let .stream(_, urlRequest):
let urlRequest = try urlRequest.adapt(using: adapter)
task = queue.syncResult { session.uploadTask(withStreamedRequest: urlRequest) }
}
return task
} catch {
throw AdaptError(error: error)
}
}
}