URLSession 是 Apple 强大的 API,我们可以使用它在 iOS 应用程序中下载和上传数据
URLSession 是一个对象,负责处理 iOS 中的 http 和 https 请求。它要求 URLSessionConfiguration 对象向 Web 服务发送和接收请求。下面是一个关于 URLSession 类的简单依赖关系图:
URLSession 有一个名为 URLSessionConfiguration 的依赖项。我们使用它来配置 http 请求属性,如缓存策略、会话类型、http 标头、超时等。当您定义会话配置时,您有三个选择:
- .default
它将创建使用磁盘持久化全局缓存、凭据和 cookie 存储对象的默认配置对象。 - .ephemeral
类似于 .default 配置,除非会话相关的数据会保存在内存中。 - .background
它将为下载和上传任务创建一个后台会话,它可以恢复或取消,并且可以在应用程序终止或终止后继续任务。
在上图中,您可以看到 URLSessionDataTask。它是一个抽象的对象,代表现实生活中请求的真实工作。URLSession 可以创建多个任务来处理一些用例,例如获取数据、下载和上传文件。共有三种类型的任务:
- URLSessionDataTask
我们可以使用此任务通过 GET 方法从 Web 服务检索数据。 - URLSessionUploadTask
我们可以使用此任务使用 POST 或 PUT 方法将数据上传到 Web 服务。 - URLSessionDownloadTask
我们可以使用此任务从 Web 服务下载文件并将其保存到临时本地存储。
通常,我们可以通过两种方式从 URLSession 中获取请求的结果。首先,我们可以对结果使用闭包完成处理程序,无论是否成功。其次,如果我们在定义 URLSession 对象时设置了委托属性,我们就可以使用委托。
以下是有关如何使用 URLSession 从 Web 服务获取数据的简单示例:
final class ExampleNetworkService {
private let urlSession: URLSession
private var dataTask: URLSessionDataTask?
init(sessionConfiguration: URLSessionConfiguration) {
self.urlSession = URLSession(configuration: sessionConfiguration)
}
func request(url: String, query: String?, httpMethod: String, completion: @escaping (Result<Data, Error>) -> Void) {
dataTask?.cancel()
guard var urlComponents = URLComponents(string: url) else {
return
}
if let urlQuery = query {
urlComponents.query = urlQuery
}
guard let validUrl = urlComponents.url else {
return
}
var urlRequest = URLRequest(url: validUrl)
urlRequest.httpMethod = httpMethod
dataTask = urlSession.dataTask(with: urlRequest, completionHandler: { [weak self] (data: Data?, response: URLResponse?, error: Error?) in
do {
self?.dataTask = nil
}
guard error == nil else {
let error = NSError(domain: "invalid endpoint", code: 900013, userInfo: nil)
completion(.failure(error))
return
}
if let data = data, let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 {
completion(.success(data))
return
} else {
let error = NSError(domain: "invalid response", code: 900014, userInfo: nil)
completion(.failure(error))
}
})
dataTask?.resume()
}
}
下面是上面示例代码中发生的事情:
在 ExampleNetworkService 类中,它有两个属性,即 URLSession 和 URLSessionDataTask 实例。在初始化程序中,我们将会话配置定义为参数。通过这个实现,我们可以在使用 – ExampleNetworkService 类时注入任何我们想要的会话配置。
我们有一个叫做 request 的函数。它需要一些参数,如 url、query、http 方法和使用 Result 类型的完成处理程序。在函数内部,它基本上验证 url、设置查询并创建 url 请求对象。
定义好url请求对象之后,我们就可以从url会话中执行网络请求,并将其传递给我们之前已经定义好的数据任务。最后,我们要求数据任务恢复,因为它基本上是第一次数据任务的状态终止。
这很简单吧?您只需通过 url 请求设置 http 方法,我们就可以开始了。然后让我们配置如何使用 URLSessionDownloadTask 从 iTunes API 下载一些音乐。首先,我们创建了一个新类型来表示音乐对象。
class Music {
let artist: String
let index: Int
let name: String
let previewURL: URL
var isDownloaded = false
init(artist: String, index: Int, name: String, previewURL: URL) {
self.artist = artist
self.index = index
self.name = name
self.previewURL = previewURL
}
}
Music 类型有一些属性,如艺术家、名称和预览 URL。index 属性是我们以后处理 table view 时可以使用的辅助属性。另一个属性是 isDownloaded,默认值为 false,表示音乐是否已经下载。
接下来,我们创建代表下载对象的新类型。这对我们以后管理下载状态有很大帮助。
class Download {
var isDownloading = false
var progress: Float = 0
var resumeData: Data?
weak var downloadTask: URLSessionDownloadTask?
let music: Music
init(music: Music) {
self.music = music
}
}
Download 类有一些辅助属性,如 isDownloading,这表示音乐是否正在下载。如果您需要在 UI 中显示下载进度,progress 属性也是辅助属性。当您暂停下载并想要继续下载时,会使用恢复数据,我们稍后可以从 URLSession 对象处理它。然后 Download 类具有名为 downloadTask 的属性,它是 URLSessionDownloadTask 的实例,我们可以使用它从 Web 服务下载文件的特定任务。
下一步是创建其中包含 URLSession 的下载服务对象。
final class ExampleDownloadService {
var activeDownloads: [URL : Download] = [:]
private let downloadSession: URLSession
init(sessionConfiguration: URLSessionConfiguration, delegate: URLSessionDelegate) {
self.downloadSession = URLSession(
configuration: sessionConfiguration,
delegate: delegate,
delegateQueue: nil
)
}
}
在 ExampleDownloadService 类中,它具有名为 activeDownloads 字典的属性。我们可以使用它来跟踪当前时间是否有任何活动下载。接下来,我们定义下载会话,它是 URLSession 的一个实例。在初始化器中,我们有两个参数,即会话配置和 URLSessionDelegate。有了这个实现我们就可以根据自己的需要注入session配置了,这次我们需要实现URLSessionDelegate来处理后面下载任务的完成。
现在我们的下载服务已经准备好了,我们可以继续执行服务内部的下载任务了。在服务内部,我们有四个用例,分别是启动、取消、暂停和恢复下载。
func startDownload(_ music: Music) {
let download = Download(music: music)
download.downloadTask = downloadSession.downloadTask(with: music.previewURL)
download.downloadTask?.resume()
download.isDownloading = true
activeDownloads[music.previewURL] = download
}
func cancelDownload(_ music: Music) {
guard let download = activeDownloads[music.previewURL] else {
return
}
download.downloadTask?.cancel()
activeDownloads[music.previewURL] = nil
download.isDownloading = false
}
func pauseDownload(_ music: Music) {
guard let download = activeDownloads[music.previewURL] else {
return
}
download.downloadTask?.cancel(byProducingResumeData: { (resumeData: Data?) in
download.resumeData = resumeData
})
download.isDownloading = false
}
func resumeDownload(_ music: Music) {
guard let download = activeDownloads[music.previewURL] else {
return
}
if let resumeData = download.resumeData {
download.downloadTask = downloadSession.downloadTask(withResumeData: resumeData)
} else {
download.downloadTask = downloadSession.downloadTask(with: music.previewURL)
}
download.downloadTask?.resume()
download.isDownloading = true
}
当您要开始下载或取消下载时,这非常简单。调用 可以启动resume()下载任务,调用cancel()函数可以取消下载任务。
但是当你想暂停下载时,它有点不同。这意味着您想稍后继续下载,对吗?幸运的是,这很简单。您可以调用另一个取消功能,这时候您要取消下载还需要恢复数据。恢复数据包含继续下载所需的所有信息。将简历数据保存在下载对象中。
然后如果你想继续下载,你可以从下载对象中提取简历数据。如果存在,那么您可以启动下载会话并将恢复数据传递给提供的参数。否则,只需从头开始下载。
好的,这是很长的解释。接下来,为了处理下载任务,我们需要实现 URLSessionDelegate 方法。
extension ViewController: URLSessionDelegate {
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
// handle finished download here
}
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
// when you need to show the progress download, implement this delegate method
}
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
// implement this delegate method if you use background session configuration
}
您需要的一切都已在 URLSessionDelegate 中提供。下载是否完成,或者您是否需要配置下载进度,或者甚至当您使用后台会话配置定义后台传输时。
挑战
首先,恭喜你一直关注这篇文章到最后。正如你所看到的,这篇文章只是解释了关于 URLSession 的详细概念,缺乏实际的实现:]。如果你接受它,你的使命就是创建简单的 iOS 应用程序来实现你关于 URLSession 的所有知识。你可以玩另一个任务比如上传任务,也可以尝试设置会话配置,比如超时、缓存策略等。感谢一直支持我写一篇关于iOS开发的文章。如果您有任何反馈或建议,请告诉我。谢谢你,并在当前的大流行情况下保持安全:]。
精品教程推荐
加入我们一起学习SwiftUI
QQ:3365059189
SwiftUI技术交流QQ群:518696470
教程网站:www.openswiftui.com