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

本文共 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

发表评论

最新留言

关注你微信了!
[***.104.42.241]2023年05月07日 21时38分34秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

最新文章

linux 开启端口永久保存,linux 防火墙开启80端口永久保存 2019-08-24 11:20:29
linux运行core控制台程序,如何在Linux中从.NET Core 2.0创建可执行控制台应用程序?... 2019-08-24 11:20:28
linux 用不用虚拟机,2018-06-10-不用虚拟机搭建Linux环境 2019-08-24 11:20:28
linux脚本给变量赋多个值,shell for循环、循环变量值付给其他shell脚本的方法 2019-08-24 11:20:27
linux系统查询数据库密码忘了怎么办,Linux下忘记MySQL数据库密码的解决方法 2019-08-24 11:20:27
linux实时进程定义,Linux进程基本概念 2019-08-24 11:20:26
linux用户进程的栈在用户态,linux的用户态程序栈的跟踪方法 2019-08-24 11:20:26
linux下tomcat部署web,Linux下安装Tomcat服务器和部署Web应用 2019-08-24 11:20:25
oracle 使用 grouping 函数可以,Oracle GROUPING函数的使用 2019-08-24 11:20:25
使用oracle数据库的程序,oracle官方文档之数据库用户使用oracle组件或第三方应用程序时所... 2019-08-24 11:20:24
php怎么写视频审核代码,媒体审核 2019-08-24 11:20:24
oracle avdf fga,Oracle Database Security Assessment Tool (DBSAT) (Doc ID 2138254.1) 2019-08-24 11:20:23
in array php 坑,php – 为什么in_array()返回意外/奇怪的结果? 2019-08-24 11:20:22
oracle的CPU补丁和PSU补丁,[Oracle] Data Guard CPU/PSU补丁安装详细教程 2019-08-24 11:20:22
incarnation oracle,对rman中的incarnation(化身)详解 2019-08-24 11:20:21
oracle11g索引优化器,【oracle 性能优化】组合索引查询。 2019-08-24 11:20:21
jdbc oracle 函数,jdbc中调用oracle函数 2019-08-24 11:20:20
Oracle 中update from,oracle中update的细节 2019-08-24 11:20:20
微信你scope 参数错误 php,微信开发: scope参数错误或没有scope权限解决方法 2019-08-24 11:20:19
php 图片切换间隔时间,js实现多张图片每隔一秒切换一张图片 2019-08-24 11:20:19