Networking with URLSession二 上传&下载
发布日期:2022-03-18 08:27:47 浏览次数:32 分类:技术文章

本文共 6318 字,大约阅读时间需要 21 分钟。

内容来自学习等系列课程,记录学习笔记

Networking with URLSession二 上传&下载

下载和上传Task

URLSessionDownloadTask

直接把服务器的响应写入到一个临时文件中,并提供进度更新。如果在background session中使用download task,即使app程序被暂停或未运行,这些下载也会继续下载。

URLSession创建download task的方式

func downloadTask(with: URL,completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void)func downloadTask(with: URLRequest,completionHandler: @escaping (URL?, URLResponse?, Error?) -> Void)

downloadTask把数据保存在一个临时的文件中,所以在completion handler返回之前,必须读取和处理文件,或者把文件copy到一个永久的位置。否则文件会被删除,data会丢失。

func downloadTask(with: URL)func downloadTask(with: URLRequest)

在调用过程中:

  • session会周期性的调用代理方法,提供一些状态信息
  • 在成功时调用方法或者一个completion回调。在这个方法中,你要么打开这个文件来读取,要么把这个文件移动到沙盒中的一个永久的位置
  • 失败时调用方法或者一个completion回调

一个download task如果在完成之前被取消或者下载失败,可以保存resume data,并继续下载。

func cancel(byProducingResumeData:@escaping (Data?) -> Void)func downloadTask(withResumeData: Data,completionHandler: @escaping (URL?,URLResponse?, Error?) -> Void)func downloadTask(withResumeData: Data)

与、不同,NSURLSessionDownloadTask通过HTTP状态码,把服务器错误,报告给响应的NSError对象:

Server-side errors NSErrors
401 Unauthorized NSURLErrorUserAuthenticationRequired
403 Forbidden NSURLErrorNoPermissionsToReadFile
407 Proxy Authentication Required NSURLErrorUserAuthenticationRequired
Other NSURLErrorFileDoesNotExist

URLSessionUploadTask

与download task类似。可直接通过completionHandler来处理结果,而不通过代理

如下,上传data数据:

func uploadTask(with: URLRequest, from: Data?,completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void)func uploadTask(with: URLRequest, from: Data)

但是不能直接使用URL来创建upload task,需要通过URLRequest来创建。因为upload task的http请求,需要http body。

除了上传data数据外,还可以上传file:

func uploadTask(with: URLRequest, fromFile: URL,completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void)func uploadTask(with: URLRequest, fromFile: URL)

另外还有一个stream request

func uploadTask(withStreamedRequest: URLRequest)

各种优先级

1.URLSessionConfigurationnetworkServiceType属性对标准的网络流量,网络电话,语音,视频,以及由一个后台进程使用的流量进行了区分。值可为default, voip, video, background, voice

2.URLSessionTaskpriority属性。即你希望host处理任务的相对优先级。0.0 (lowest)1.0 (highest), default是0.5
3.URLRequestnetworkServiceType。可重写配置对象的networkServiceType
4.URLSession’s delegateQueuequalityOfService: userInteractive, userInitiated, utility, background

缓存

大量的下载可以很好的利用缓存来减少网络拥堵的问题。Default configuration使用的是一个持久的基于disc的cache。

cache会减少app对网络连接的依赖,提高的app的性能。
默认的cache policy使用的是protocol的cache policy,而protocol通常是HTTP。

缓存流程

参考文档:


下载

本例下载,是下载音频示例,如:

http://audio.itunes.apple.com/apple-assets-us-std-000001/AudioPreview30/v4/02/4e/35/024e3534-92b4-6e6d-217e-b5714b6faa20/mzaf_5572571419358472776.plus.aac.p.m4a

开始下载资源

代码如下:

func startDownload(_ track: Track) {    let download = Download(url: track.previewURL)    //下载任务    download.task = defaultSession.downloadTask(with: track.previewURL) { location, response, error in      self.saveDownload(download: download, location: location, response: response, error: error)    }    download.task!.resume()    download.isDownloading = true    activeDownloads[download.url] = download  }  func saveDownload(download : Download, location : URL?, response : URLResponse?, error : Error?) {    let sourceURL = download.url    if error != nil { return }    activeDownloads[sourceURL] = nil    //copy目的地地址    let destinationURL = localFilePath(for: sourceURL)    //先移除在复制    let fileManager = FileManager.default    try? fileManager.removeItem(at: destinationURL)    do {      try fileManager.copyItem(at: location!, to: destinationURL)    } catch let error {      print("Could not copy file to disk: \(error.localizedDescription)")    }    //更新UI    if let index = trackIndex(for: download.task!) {      DispatchQueue.main.async {        self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)      }    }  }

暂停下载

//暂停下载  func pauseDownload(_ track: Track) {    guard let download = activeDownloads[track.previewURL] else { return }    //处理已下载的数据    download.task!.cancel(byProducingResumeData: { (data) in      download.resumeData = data    })    download.isDownloading = false    //更新UI    if let index = trackIndex(for: download.task!) {      DispatchQueue.main.async {        self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)      }    }  }

取消下载

//取消下载  func cancelDownload(_ track: Track) {    guard let download = activeDownloads[track.previewURL] else { return }    //取消下载    download.task!.cancel()    download.isDownloading = false    activeDownloads[track.previewURL] = nil    if let index = trackIndex(for: download.task!) {      DispatchQueue.main.async {        self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)      }    }  }

继续下载

// 继续下载  func resumeDownload(_ track: Track) {    guard let download = activeDownloads[track.previewURL] else { return }    if let resumeData = download.resumeData {      //在原来的数据上继续下载      download.task = defaultSession.downloadTask(withResumeData: resumeData, completionHandler: { (location, response, error) in        self.saveDownload(download: download, location: location, response: response, error: error)      })    }else {      //重新下载      download.task = defaultSession.downloadTask(with: download.url, completionHandler: { (location, response, error) in        self.saveDownload(download: download, location: location, response: response, error: error)      })    }    download.task!.resume()    download.isDownloading = true    if let index = trackIndex(for: download.task!) {      DispatchQueue.main.async {        self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)      }    }  }

上传

上传以上一节的PostRouter为例,上传json数据

let session = URLSession(configuration: .ephemeral)let putRequest = PostRouter.update(1, ["author": "Part 6", "title": "Upload Task"]).asURLRequest()typealias JSONDictionary = [String: Any]let putTask = session.uploadTask(with: putRequest, from: putRequest.httpBody) { data, response, error in  defer { PlaygroundPage.current.finishExecution() }  guard let data = data, let response = response as? HTTPURLResponse,    response.statusCode == 200 else {      print("No data or statusCode not OK")      return  }  var jsonResult: JSONDictionary  do {    let result = try JSONSerialization.jsonObject(with: data, options: [])    jsonResult = result as! JSONDictionary  } catch {    print(error.localizedDescription)    return  }}putTask.resume()

其它文档

转载地址:https://windzen.blog.csdn.net/article/details/70308367 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Mosaic布局(类似于瀑布流)
下一篇:Text Kit入门——Beginning Text Kit

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月09日 05时58分26秒