在前面的幾篇文章中已經介紹了Alamofire的request。本篇咱們一塊兒來了解一下response。swift
說到response不少小夥伴都會和序列化聯繫起來,那麼Alamofire的response的做用究竟是什麼呢?數組
咱們來看個栗子🌰:網絡
let urlBD = "https://www.baidu.com"
Alamofire.request(urlBD, method: .get, parameters: ["user": "bo"])
.response { (response) in
print(response)
}
複製代碼
運行結果會打印不少內容,因篇幅緣由就不貼圖了,就留給小夥伴自行玩耍吧。session
這些 response
中的內容是如何來的呢?咱們一塊兒來看看源碼。 閉包
從源碼能夠看出,response
函數並無作序列化的處理。而是使用 Request
的 self.request
、self.response
、self.delegate
、self.timeline
屬性封裝成一個新的對象 DefaultDataResponse
返回給 completionHandler
閉包。app
由於 response
函數是 DataRequest
的擴展。因此 self.request
、self.response
比較容易理解。那麼 self.delegate.data
是什麼呢?咱們點擊查看源碼: dom
能夠看到,若是 dataStream
閉包爲空,則返回 mutableData 。因此咱們再繼續查看 mutableData
是何時賦值的。 異步
咱們找到在 func urlSession(session:dataTask:didReceive:)
回調中,返回的數據 data
會被添加到 mutableData
中。函數
爲何須要 mutableData
呢?由於請求的數據多是分段返回的,因此須要一箇中間變量來存儲每次返回的數據。工具
和 self.delegate.data
相似, self.delegate.error
也是在回調函數 didCompleteWithError
中判斷,若是有錯誤,則給 error
賦值。
至於 self.timeline
,咱們在上一篇 Alamofire之request補充 已有介紹,這裏再也不贅述,想了解的小夥伴請移步。
綜上,能夠總結出,其實
response
函數並無作其餘處理,僅作爲保存數據和返回數據的載體,其整合了request請求的各個返回結果,做爲一個總體返回給用戶,供用戶隨時取用。
在查看 response
函數源碼的時候,若是往下翻小夥伴可能會發現另外一個 reponse
函數。
這個 response
函數和上一個相比,多了一個 responseSerializer
參數,這個參數就是序列化器。
那麼這個 response
函數該如何使用呢?咱們先來分析 responseSerializer
參數是個什麼類型。
responseSerializer
的參數是一個泛型。泛型須要實現一個協議: DataResponseSerializerProtocol。
同時咱們在其下方發現一個已經實現該協議的類型 DataResponseSerializer
。
因此咱們可使用這個類做爲序列化器。
let urlBD = "https://www.baidu.com"
Alamofire.request(urlBD, method: .get, parameters: ["user": "bo"])
.response { (response) in
print(response)
}
.response(responseSerializer: DataResponseSerializer<String>.init(serializeResponse: { (request, response, data, error) -> Result<String> in
if error == nil {
return .success("網絡請求成功")
} else {
return .failure(NSError(domain: "網絡請求失敗", code: 10080, userInfo: nil))
}
})) { (reponse) in
print("序列化結果: \(reponse)")
}
複製代碼
DataResponseSerializer
初始化須要傳入一個閉包,且閉包的返回值爲 Result
類型。
從運行結果會發現,在打印出未序列化的 reposne
以後,會再打印出序列化後的結果。
以上就是response序列化器的分析,包括 Alamofire提供的
responseJSON
函數,其內部僅是對 JSON序列化器作了一次封裝而已。
先舉個栗子🌰:
let url = "http://www.baidu.com/"
Alamofire.upload(multipartFormData: { (formData) in
formData.append("BO".data(using: .utf8)!, withName: "name")
formData.append("122345".data(using: .utf8)!, withName: "pwd")
}, to: url) { (result) in
print(result)
}
複製代碼
上面👆這段代碼就是多表單上傳的例子。而後使用抓包工具 Charles 抓包。
就能夠看到如上所示的結果。
其實在進行多表單上傳時,須要將表單數據按照必定的格式(如上圖)封裝到httpBody中。具體格式請小夥伴自行google。
那麼Alamofire是如何封裝的呢?咱們一路查看源碼,很容易就能找到這裏:
首先由於在讀取數據時多是一個耗時操做,因此
MultipartFormData
對象。multipartFormData
閉包,拼接表單數據。Content-Type
,代表這是一個表單數據,以及 boundary
邊界信息。formData.encode()
格式化數據。咱們在向表單中添加數據時,會調用 append
函數添加數據。
在 append
函數中,參數 name
會被先傳入 contentHeaders
函數中進行處理。
通過處理後會成爲咱們所須要的格式。
而後再將格式化後的 headers
和 data
封裝成 BodyPart
對象。
最後添加到 bodyParts
數組中保存起來。
須要格式化表單時,會調用 encode
函數。
encode
函數會將 bodyParts
中的首尾兩個元素分別設置 hasInitialBoundary = true
和 hasFinalBoundary = true
,標識出其是首尾元素。
再遍歷 bodyParts
數組中的元素,對每個元素分別進行 encode
。
一、格式化邊界
首先經過 hasInitialBoundary
判斷是首元素仍是中間元素。
initialBoundaryData()
函數。encapsulatedBoundaryData()
函數。finalBoundaryData()
函數。這三個函數調用的都是 boundaryData
函數,僅參數不一樣。
因此,最後生成的邊界格式會有所不一樣。如: 首元素:--alamofire.boundary.xxx 中間元素:--alamofire.boundary.xxx 尾元素:--alamofire.boundary.xxx--
二、格式化name
對每一個元素調用 encodeHeaders
函數。
最後生成格式以下: Content-Disposition: form-data; name="name"
三、格式化data
對每一個元素調用 encodeBodyStream
函數。
由於表單數據多是一個很大的文件,若是要將文件整個讀取到內存中,將會消耗掉很大的內存空間,形成資源緊張。因此使用 數據流stream 的方式讀取數據。生成格式如:BO。
最後將生成的全部數據拼接爲一個data數據,完成表單數據的封裝。
以上,則是多表單上傳中,表單數據的格式化解析。