URLSession基本使用

简述

由于最近想要研究下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就是要上传的数据,非表单数据不需要对数据进行处理,使用这个函数上传的时候会自动忽略httpBodyhttpStream,上传表单数据的时候要复杂一些,需要先对数据进行一些处理,如下:

    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-typemultipart/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

你可能感兴趣的:(URLSession基本使用)