自己動(dòng)手寫(xiě)一個(gè) iOS 網(wǎng)絡(luò)請(qǐng)求庫(kù)——降低耦合
開(kāi)源項(xiàng)目:Pitaya,適合大文件上傳的 HTTP 請(qǐng)求庫(kù):https://github.com/johnlui/Pitaya
本文中,我們將一起降低之前代碼的耦合度,并使用適配器模式實(shí)現(xiàn)一層獨(dú)立于底層結(jié)構(gòu)的網(wǎng)絡(luò) API,造一個(gè)真正的網(wǎng)絡(luò)請(qǐng)求“庫(kù)”。
降低耦合度
如何降低耦合度
現(xiàn)在的清湯掛面式的代碼雖然便于理解,但是功能單一,代碼雜亂。我們一起來(lái)分析 NSURLSession 的使用過(guò)程:
構(gòu)造 NSURLRequest
確定 URL
確定 HTTP 方法(GET、POST 等)
添加特定的 HTTP 頭
填充 HTTP Body
驅(qū)動(dòng) session.dataTaskWithRequest 方法,開(kāi)始請(qǐng)求
具體實(shí)施
在 Network 下另外新建一個(gè) NetworkManager 類(lèi),將 URL、params、files 等設(shè)為成員變量,讓他們?cè)跇?gòu)造函數(shù)中初始化:
- class NetworkManager {
- let method: String!
- let params: Dictionary let callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void
- let session = NSURLSession.sharedSession()
- let url: String!
- var request: NSMutableURLRequest!
- var task: NSURLSessionTask!
- init(url: String, method: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
- self.url = url
- self.request = NSMutableURLRequest(URL: NSURL(string: url)!)
- self.method = method
- self.params = params
- self.callback = callback
- }
- }
之后,將上面分析的
1. 確定 URL
2. 確定 HTTP 方法(GET、POST 等)
3. 添加特定的 HTTP 頭
4. 填充 HTTP Body
前三步封裝到一個(gè) function 中,***一步封裝到一個(gè) function 中,然后把驅(qū)動(dòng) session.dataTaskWithRequest 的代碼封裝到一個(gè) function 中:
- func buildRequest() {
- if self.method == "GET" && self.params.count > 0 {
- self.request = NSMutableURLRequest(URL: NSURL(string: url + "?" + buildParams(self.params))!)
- }
- request.HTTPMethod = self.method
- if self.params.count > 0 {
- request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
- }
- }
- func buildBody() {
- if self.params.count > 0 && self.method != "GET" {
- request.HTTPBody = buildParams(self.params).nsdata
- }
- }
- func fireTask() {
- task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
- self.callback(data: data, response: response, error: error)
- })
- task.resume()
- }
之后使用一個(gè)統(tǒng)一的方法來(lái)驅(qū)動(dòng)上面三個(gè) function,完成請(qǐng)求:
- func fire() {
- buildRequest()
- buildBody()
- fireTask()
- }
同時(shí),不要忘了那三個(gè) parse params 的從 Alamofire 偷來(lái)的函數(shù)哦,也要放到這個(gè)類(lèi)里面。至此,降低耦合的工作基本完成,接下來(lái)我們開(kāi)始封裝“網(wǎng)絡(luò)API”。
使用適配器模式封裝“網(wǎng)絡(luò)API”
理解適配器模式
適配器模式是設(shè)計(jì)模式中的一種,很容易理解:我的 APP 需要一個(gè)獲取某一個(gè) URL 返回的字符串的功能,我現(xiàn)在選擇的是 Alamofire,但是正在發(fā)展的 Pitaya 看起來(lái)不錯(cuò),我以后想替換成 Pitaya,所以我封裝了一層我自己的網(wǎng)絡(luò)接口,用來(lái)屏蔽底層細(xì)節(jié),到時(shí)候只需要修改這個(gè)類(lèi),不需要再深入項(xiàng)目中改那么多接口調(diào)用了。
適配器模式聽(tīng)起來(lái)高大上,其實(shí)這是我們?cè)谌粘>幋a中非常常用的設(shè)計(jì)模式。
Do it!
修改 Network 類(lèi)的代碼為:
- class Network{
- static func request(method: String, url: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
- let manager = NetworkManager(url: url, method: method, params: params, callback: callback)
- manager.fire()
- }
- }
搞定!
封裝多級(jí)接口
不帶 params 的接口:
- static func request(method: String, url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
- let manager = NetworkManager(url: url, method: method, callback: callback)
- manager.fire()
- }
兩個(gè) get 接口(帶與不帶 params):
- static func get(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
- let manager = NetworkManager(url: url, method: "GET", callback: callback)
- manager.fire()
- }
- static func get(url: String, params: Dictionary, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
- let manager = NetworkManager(url: url, method: "GET", params: params, callback: callback)
- manager.fire()
- }
兩個(gè) post 接口(帶與不帶 params):
- static func post(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
- let manager = NetworkManager(url: url, method: "POST", callback: callback)
- manager.fire()
- }
- static func post(url: String, params: Dictionary, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
- let manager = NetworkManager(url: url, method: "POST", params: params, callback: callback)
- manager.fire()
- }
測(cè)試接口
修改 ViewController 中的調(diào)用代碼,測(cè)試多級(jí) API:
- @IBAction func mainButtonBeTapped(sender: AnyObject) {
- let url = "http://pitayaswift.sinaapp.com/pitaya.php"
- Network.post(url, callback: { (data, response, error) -> Void in
- println("POST 1 請(qǐng)求成功")
- })
- Network.post(url, params: ["post": "POST Network"], callback: { (data, response, error) -> Void in
- let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
- println("POST 2 請(qǐng)求成功 " + string)
- })
- Network.get(url, callback: { (data, response, error) -> Void in
- println("GET 1 請(qǐng)求成功")
- })
- Network.get(url, params: ["get": "POST Network"], callback: { (data, response, error) -> Void in
- let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
- println("GET 2 請(qǐng)求成功 " + string)
- })
- Network.request("GET", url: url, params: ["get": "Request Network"]) { (data, response, error) -> Void in
- let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String
- println("Request 請(qǐng)求成功 " + string)
- }
- }
運(yùn)行項(xiàng)目,點(diǎn)擊按鈕,查看效果:
多級(jí) API 封裝成功!