iOS网络协议栈原理(二) — URLSessionTask层
上一篇文章总结到, URLSession
是一个出产URLSessionDataTask
的工厂, 其中有几个要害内二进制的运算规则容, 会在这一节中解释:
- 在创立
task
时, 会初始化失败是怎么解决将URLSession
实例传入, 也二进制便是说task
可能会在内部持有URLSession
- 真实建议恳求时, 需求调用
task.resume()
办法 — 那么Ta状态机是什么sk
究竟是如何作业的
1. Task
的初始化创立与HTTP B容器是什么ody
包装
简略概括一下Task的初始化的要害信息:
- Task的回调办法: 相关回调办法, 是经过
Behavappearanceiour + taskIdentifier
存状态机的概念储在URLSession
中 -
_Body枚举
: 根据URLReqapproachuest
的httpBody or httpBodyStream
的成员, 在内部一致运用_Bo状态机模式dy枚举
收口, 具会分成4类. - 参阅以下代码注释
open class URLSessionTask : NSObject, NSCopying { ... // 结构 SessionTask 的 Body 可能有4种情况 enum _Body { case none case data(DispatchData) // 为啥用 DispatchData 是一个内部二进制容器类型, 实际会避免copy, 和传入的 request.httpBody 共用同一份内存 /// Body data is read from the given file URL case file(URL) // 其他的 Task会运用 URL形式的 body case stream(InputStream) } // 中心办法! internal convenience init(session: URLSession, request: URLRequest, taskIdentifier: Int) { if let bodyData = request.httpBody, !bodyData.isEmpty { self.init(session: session, request: request, taskIdentifier: taskIdentifier, body: _Body.data(createDispatchData(bodyData))) } else if let bodyStream = request.httpBodyStream { self.init(session: session, request: request, taskIdentifier: taskIdentifier, body: _Body.stream(bodyStream)) } else { // 其他场景, 没有body -> 例如运用 GET 恳求时 self.init(session: session, request: request, taskIdentifier: taskIdentifier, body: _Body.none) } } // 更加重要的办法 internal init(session: URLSession, request: URLRequest, taskIdentifier: Int, body: _Body?) { // 1. task 会强引证创立它的 session, 而且在 task 完毕的时候 self.session = nil self.session = session // 2. 将 workQueue的 targetQueue 设置成 session.workQueue // 3. 后续有很多关于 task.state 的操作都在这个 serial queue 中完结!!! self.workQueue = DispatchQueue.init(label: "org.swift.URLSessionTask.WorkQueue", target: session.workQueue) // 4. 仅有 task Identifier, 运用这个仅有标记, 可以经过 URLSession 相关 CompletionHandler self.taskIdentifier = taskIdentifier // 5. 持有一份外部传入的 Request!!! 因为整个恳求进程中, 可能遇到 HTTP Status Code = 302的情况, 需求重定向, 可能一次Task进程会建议多个恳求 self.originalRequest = request // 原始的恳求 // 6. 收口今后的 http body self.knownBody = body super.init() // 7. 同 5, 初始化时, 当前的恳求便是初始化的request (后边如果有302重定向场景, Task会创立一个新的指向重定向路径的request, 那时会修改 currentRequest) self.currentRequest = request // 8. 疏忽... self.progress.cancellationHandler = { [weak self] in self?.cancel() } } }
2. Task
的内部状态机
前面我们知道, 在运用Session
工厂, 创立Task
实例今后,二进制的运算规则 需求主动调用task.resume()
办法发动这个使命
!!!初始化是什么意思 why??初始化sdk什么意思?
实际上在task内部维护了一个state
!!! 而且经过一个成员变量s容器英文uspend容器的容积一定比它的体积小Coun初始化磁盘t
来记录这个Tappearask使命
是否在挂起appstore状态!!!
extension URLSessionTask { /// How many times the task has been suspended, 0 indicating a running task. internal var suspendCount = 1 public enum State : Int { /// The task is currently being serviced by the session case running case suspended // 初始是 suspended /// The task has been told to cancel. The session will receive a URLSession:task:didCompleteWithError: message. case canceling // 退出 ing!!!!!! 只是标记 canceling -> 可是没 completed /// The task has completed and the session will receive no more delegate notifications case completed } /// Updates the (public) state based on private / internal state. /// /// - Note: This must be called on the `workQueue`. internal func updateTaskState() { func calculateState() -> URLSessionTask.State { if suspendCount == 0 { return .running } else { return .suspended } } state = calculateState() } // 中心办法 open func resume() { workQueue.sync { // 疏忽 canceling 和 completed guard self.state != .canceling, self.state != .completed else { return } if self.suspendCount > 0 { self.suspendCount -= 1 } self.updateTaskState() if self.suspendCount == 0 { ... // 真实的发动使命 } } } // 中心办法 open func cancel() { workQueue.sync { let canceled = self.syncQ.sync { () -> Bool in guard self._state == .running || self._state == .suspended else { return true } self._state = .canceling return false } guard !canceled else { return } ... } } }
经过以上代码能看出task
的两个中心办法, 首要便是切换task.state
, 而且关于state
的操作都是在workQueue
中完结的:
- 初始化时,
task.state => .suspe初始化失败是怎么解决nded
- 当外部调用
resume()
,task.state => .running
, 然后真实发动耗时使命, 详细的耗时使命是交给别的一个URLP容器是什么rotocl状态机编程的实例
完结的, 详细发动使命的逻辑我们后边分析!!! - 当外部调用
cance()
,task.st容器苗ate => .canceling
, 表明task
现已撤销, 然后去处理底层的资源清理作业 - 在
task
相关的URLProtocl的实例
的清理作业完结今后, 会调用task.state => .completed
!!!
因此, 简略来说, Task
并不是自己去履行网络恳求approve, 而是又笼统了一层, 真实的苦力活都是交给URLProtoco状态机l
去做的!!!
别的Task
功能性不同, Apple 创立状态机编程多个子类来进行差异化使命的实现, 别的, task progress
以及HTTP 302
重定向等逻辑都是在task层
实现的:
open class URLSessionDataTask: URLSessionTask {} /* * An URLSessionUploadTask does not currently provide any additional * functionality over an URLSessionDataTask. All delegate messages * that may be sent referencing an URLSessionDataTask equally apply * to URLSessionUploadTasks. */ open class URLSessionUploadTask: URLSessionDataTask {} /* * URLSessionDownloadTask is a task that represents a download to * local storage. */ open class URLSessionDownloadTask: URLSessionTask { ... }
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。
评论(0)