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)