Swift - 异步编程库PromiseKit使用详解2(URLSession的扩展)
作者:hangge | 2018-12-06 08:10
PromiseKit 不仅仅是一个简单的异步编程框架,它还为 Apple API 提供了许多扩展,对原有的 API 构建一个新的 Promise 实现,方便我们使用。
三、URLSession 的扩展
1,安装配置
(1)首先要安装 PromiseKit 库,具体步骤可以参考我之前的文章:
(2)接着安装 PromiseKit 的 Foundation 扩展库,从 GitHub 上下载最新的代码:
(3)将下载下来的源码包中 PMKFoundation.xcodeproj 拖拽至你的工程中
(4)工程 -> General -> Embedded Binaries 项,把 PMKFoundation.framework 添加进来。
import PMKFoundation
2,使用 Data Task 加载数据
(1)下面样例发起一个网络请求,并将请求结果打印出来:
import UIKit import PromiseKit import PMKFoundation class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //创建URL对象 let urlString = "https://httpbin.org/get?foo=bar" let url = URL(string:urlString) //创建请求对象 let request = URLRequest(url: url!) //请求数据 _ = URLSession.shared.dataTask(.promise, with: request) .validate() //这个也是PromiseKit提供的扩展方法,比如自动将 404 转成错误 .done { data, response in let str = String(data: data, encoding: String.Encoding.utf8) print("--- 请求结果如下 ---") print(str ?? "") } } }
(2)下面样例同样是发起一个网络请求,不过这次我们将请求结果转换成对象。
import UIKit import PromiseKit import PMKFoundation class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() //请求数据 fetchData(args: "foo=bar") .done { data in print("--- 请求结果 ---") print(data) }.catch { error in print("--- 请求失败 ---") print(error) } } //请求数据 func fetchData(args: String) -> Promise<Any>{ //创建URL对象 let urlString = "https://httpbin.org/get?\(args)" let url = URL(string:urlString) //创建请求对象 let request = URLRequest(url: url!) //使用PromiseKit的URLSession扩展方法获取数据 return URLSession.shared.dataTask(.promise, with: request) .validate() //这个也是PromiseKit提供的扩展方法,比如自动将 404 转成错误 .map { //将请求结果转成对象 try JSONDecoder().decode(HttpBin.self, from: $0.data) } } } //请求结果对象 struct HttpBin: Codable { var origin: String var url: String }
(3)当然我们也可以同时发起多个网络请求,等它们都返回后一起处理。
//请求数据 when(fulfilled: fetchData(args: "foo=bar"), fetchData(args: "name=hangge")) .done { data1, data2 in print("--- 请求结果1 ---") print(data1) print("--- 请求结果2 ---") print(data2) }.catch { error in print("--- 请求失败 ---") print(error) }
3,使用 Download Task 来下载文件
func sessionSimpleDownload(){ //下载地址 let url = URL(string: "http://hangge.com/blog/images/logo.png") //请求 let request = URLRequest(url: url!) let session = URLSession.shared //文件保存路径 let savePath = URL(fileURLWithPath: NSHomeDirectory() + "/Documents/1.png") //下载任务 _ = session.downloadTask(.promise, with: request, to: savePath) .done { saveLocation, response in print("下载成功!保存地址如下:") print(saveLocation) }.catch { error in print("下载失败!错误信息如下:") print(error.localizedDescription) } }
4,使用 Upload Task 来上传文件
func sessionUpload(){ //上传地址 let url = URL(string: "http://hangge.com/upload.php") //请求 var request = URLRequest(url: url!, cachePolicy: .reloadIgnoringCacheData) request.httpMethod = "POST" let session = URLSession.shared //上传数据流 let documents = NSHomeDirectory() + "/Documents/1.png" let imgData = try! Data(contentsOf: URL(fileURLWithPath: documents)) //上传任务 _ = session.uploadTask(.promise, with: request, from: imgData) .done { data, response in print("上传成功!") }.catch { error in print("下载失败!错误信息如下:") print(error.localizedDescription) } }
附:服务端代码(upload.php)
<?php /** php 接收流文件 * @param String $file 接收后保存的文件名 * @return boolean */ function receiveStreamFile($receiveFile){ $streamData = isset($GLOBALS['HTTP_RAW_POST_DATA'])? $GLOBALS['HTTP_RAW_POST_DATA'] : ''; if(empty($streamData)){ $streamData = file_get_contents('php://input'); } if($streamData!=''){ $ret = file_put_contents($receiveFile, $streamData, true); }else{ $ret = false; } return $ret; } //定义服务器存储路径和文件名 $receiveFile = $_SERVER["DOCUMENT_ROOT"]."/uploadFiles/hangge.png"; $ret = receiveStreamFile($receiveFile); echo json_encode(array('success'=>(bool)$ret)); ?>
如何在上传时附带上文件名?
有时我们在文件上传的同时还会想要附带一些其它参数,比如文件名。这样服务端接收到文件后,就可以根据我们传过来的文件名来保存。实现这个其实很简单,客户端和服务端分别做如下修改。
有时我们在文件上传的同时还会想要附带一些其它参数,比如文件名。这样服务端接收到文件后,就可以根据我们传过来的文件名来保存。实现这个其实很简单,客户端和服务端分别做如下修改。
- 客户端:将文件名以参数的形式跟在链接后面。比如:http://hangge.com/upload.php?fileName=image1.png
- 服务端:通过 $_GET["fileName"] 得到这个参数,并用其作为文件名保存。
全部评论(0)