简述
由于最近想要研究下Swift中第三方网络请求库Alamofire的使用和实现,而Alamofire中又是使用URLSession进行封装的,所以有必要去先深入了解下URLSession。URLSession等同于NSURLSession,只是前者是Swift中的名字,后者是OC中的名字,他们之间是可以直接相互转换的。NSURLSession是同iOS7一同推出的,主要是对NSURLConnection进行了重构和优化,并且NSURLConnection在iOS 9的时候也已经被废弃,所以NSURLSession是NSURLConnection的取代者。
URLSession层级
再使用之前我们先看一下URLSession的层级结构
- URLSession
- URLSessionconfiguration
- URLSessionTask
- URLSessionDataTask
- URLSessionUploadTask
- URLSessionDownloadTask
- URLSessionStreamTask
URLSession相关的代理方法
- URLSessionDelegate
- URLSessionTaskDelegate
- URLSessionDataDelegate
- URLSessionDownloadDelegate
- URLSessionStreamDelegate
URLSession使用的时候也会用到相关的若干类:
- NSURL
- NSURLRequest
- URLResponse
- HTTPURLResponse
- CachedURLResponse
创建URLSession
使用URLSession需要先创建一个URLSessionConfiguration实例,URLSessionConfiguration主要是URLSession上传或者下载数据时候的一些相关的配置,例如超时时间、缓存策略、等等,当然你也可以在URLRequest中进行一些相关配置
let sessionConfigure = URLSessionConfiguration.default
sessionConfigure.httpAdditionalHeaders = ["Content-Type": "application/json"]
sessionConfigure.timeoutIntervalForRequest = 30
sessionConfigure.requestCachePolicy = .reloadIgnoringLocalCacheData
let session = URLSession(configuration: sessionConfigure)
URLSessionConfiguration创建时候有三种选择,默认的、短暂的、和后台的,这个需要根据自己的需求去创建
使用URLSession
由于URLSession把网络任务进行了细分,所以我们可以根据我们的需求,选择不同的Task
普通数据请求
普通的 json 数据可以使用URLSessionDataTask
guard let url = URL(string: "http://rap.taobao.org/mockjsdata/13552/provincelist") else {
return
}
let urlRequest = URLRequest(url: url)
let dataTask = session.dataTask(with: urlRequest) { (data, response, error) in
guard let resultData = data else {
return
}
do {
let jsonObject = try JSONSerialization.jsonObject(with: resultData, options: .mutableLeaves)
print(jsonObject)
} catch {
print("解析错误!")
}
}
获取到 dataTask
以后需要使用 resume()
函数来恢复或者开始
dataTask.resume()
这样请求到数据后就会在闭包中返回数据,我们可以在闭包中进行数据处理。
上传数据
URLSession上传数据需要用到uploadTask(with request: URLRequest, from bodyData: Data?, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Swift.Void) -> URLSessionUploadTask
函数,bodyData
就是要上传的数据,非表单数据不需要对数据进行处理,使用这个函数上传的时候会自动忽略httpBody
和httpStream
,上传表单数据的时候要复杂一些,需要先对数据进行一些处理,如下:
let boundary = "Ju5tH77P15Aw350m3"
let crlf = "\r\n"
let initial = "--\(boundary)\(crlf)"
let final = "\(crlf)--\(boundary)--\(crlf)"
let contentDisposition = "Content-Disposition: form-data; name=\"image\";filename=\"image5.png\"\(crlf)"
let mimeType = "Content-Type=image/png\(crlf)"
var bodyData = Data()
guard let initialData = initial.data(using: .utf8) else {
return
}
guard let finalData = final.data(using: .utf8) else {
return
}
guard let contentDispositionData = contentDisposition.data(using: .utf8) else {
return
}
guard let mimeTypeData = mimeType.data(using: .utf8) else {
return
}
bodyData.append(initialData)
bodyData.append(contentDispositionData)
bodyData.append(mimeTypeData)
guard let imageData = UIImageJPEGRepresentation(#imageLiteral(resourceName: "Image"), 0.5) else {
return
}
bodyData.append(imageData)
bodyData.append(finalData)
let sessionConfigure = URLSessionConfiguration.ephemeral
sessionConfigure.httpAdditionalHeaders = ["Content-Type": "multipart/form-data; boundary=\(boundary)"]
sessionConfigure.timeoutIntervalForRequest = 30
sessionConfigure.requestCachePolicy = .reloadIgnoringLocalCacheData
let session = URLSession(configuration: sessionConfigure)
guard let url = URL(string: "http://picupload.service.weibo.com/interface/pic_upload.php") else {
return
}
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
let task = session.uploadTask(with: urlRequest, from: bodyData) { (data, response, error) in
guard let data = data else {
return
}
let htmlString = String.init(data: data, encoding: .utf8)
print(htmlString ?? "html")
print(response ?? "response")
}
task.resume()
这是使用上传函数的代码,由于上传数据的时候我们的请求头中Content-type
是multipart/form-data
,所以我们需要对上传的的数据进行一些处理,添加boundary
这个表示每段数据的边界,Content- Disposition
表示的是服务器端要对对数据进行的处理,添加的数据格式需要跟上边的一致,添加的每一行都需要以\r\n
结尾。
上边主要说明的是直接以Data
的形式上传的,当然也可以提供文件路径上传文件,使用方法类似。
下载数据
下载数据的时候需要用到downloadTask(with url: URL, completionHandler: @escaping (URL?, URLResponse?, Error?) -> Swift.Void) -> URLSessionDownloadTask
,下载成功以后会在闭包中返回一个存在 tem 文件夹的文件URL,由于这个文件夹下的文件随时可能被清空,所以需要把文件移动到另一个文件夹下
guard let url = URL(string: "http://172.16.2.254/php/phonelogin/image.png") else {
return
}
let session = URLSession.shared
let downloadTask = session.downloadTask(with: url) { (temURL, response, error) in
let persistentPath = NSTemporaryDirectory().appending("/\(response?.suggestedFilename ?? "image.png")")
guard let temURL = temURL else {
print("源URL不存在")
return
}
guard let persistentURL = URL(string: persistentPath) else {
print("目标路径不存在")
return
}
do {
try FileManager.default.moveItem(at: temURL, to: persistentURL)
} catch {
print("移动失败")
}
}
downloadTask.resume()
以上就是URLSession的基本使用,后续会对URLSession的代理方法,以及URLSession推流,URLCache、Cookie使用等进行梳理介绍...
未完待续
相关Demo:https://github.com/jiahongyuan5/URLSessionDemo/archive/master.zip
网友评论