自己動(dòng)手寫一個(gè) iOS 網(wǎng)絡(luò)請(qǐng)求庫(kù)——封裝接口
代碼示例:https://github.com/johnlui/Swift-On-iOS/blob/master/BuildYourHTTPRequestLibrary
開源項(xiàng)目:Pitaya,適合大文件上傳的 HTTP 請(qǐng)求庫(kù):https://github.com/johnlui/Pitaya
本篇文章中,我們將一起嘗試使用一個(gè)類來封裝我們之前的代碼,并嘗試加入動(dòng)態(tài)增加 HTTP 參數(shù)(params)的功能,之后封裝出一個(gè)強(qiáng)大的接口。
基本封裝
基礎(chǔ)準(zhǔn)備
新建一個(gè) Swift 空文件,命名為 Network.swift,在里面寫一個(gè) Network 類,之后寫一個(gè)靜態(tài)方法 request():
- class Network{
 - static func request() {
 - let session = NSURLSession.sharedSession()
 - let request = NSURLRequest(URL: NSURL(string: "http://baidu.com")!)
 - let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
 - println("just wait for 5 seconds!")
 - sleep(5)
 - let string = NSString(data: data, encoding: NSUTF8StringEncoding)
 - println(string)
 - })
 - task.resume()
 - }
 - }
 
修改 ViewController 中的按鈕函數(shù):
- @IBAction func mainButtonBeTapped(sender: AnyObject) {
 - Network.request()
 - }
 
運(yùn)行項(xiàng)目,點(diǎn)擊按鈕,效果和之前一致。
自定義 HTTP method 和 URL
修改 request() 方法,將 HTTP 方法和 URL 傳進(jìn)去:
- static func request(method: String, url: String) {
 - let session = NSURLSession.sharedSession()
 - let request = NSMutableURLRequest(URL: NSURL(string: url)!)
 - request.HTTPMethod = method
 - let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
 - println("just wait for 5 seconds!")
 - sleep(5)
 - let string = NSString(data: data, encoding: NSUTF8StringEncoding)
 - println(string)
 - })
 - task.resume()
 - }
 
修改前面的函數(shù)調(diào)用:
- @IBAction func mainButtonBeTapped(sender: AnyObject) {
 - Network.request("GET", url: "http://baidu.com")
 - }
 
運(yùn)行項(xiàng)目,點(diǎn)擊按鈕,效果和之前一致。
使用閉包處理請(qǐng)求結(jié)果
函數(shù)是 Swift 中的一等公民,閉包可以作為函數(shù)參數(shù)和返回值,十分強(qiáng)大。下面我們就用閉包來處理網(wǎng)絡(luò)請(qǐng)求的返回值。修改 request() 方法,傳遞進(jìn)去一個(gè)閉包:
- static func request(method: String, url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
 - let session = NSURLSession.sharedSession()
 - let request = NSMutableURLRequest(URL: NSURL(string: url)!)
 - request.HTTPMethod = method
 - let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
 - callback(data: data, response: response , error: error)
 - })
 - task.resume()
 - }
 
在前面函數(shù)調(diào)用處使用閉包進(jìn)行結(jié)果處理:
 
- @IBAction func mainButtonBeTapped(sender: AnyObject) {
 - Network.request("GET", url: "http://baidu.com") { (data, response, error) -> Void in
 - println("just wait for 5 seconds!")
 - sleep(5)
 - let string = NSString(data: data, encoding: NSUTF8StringEncoding)
 - println(string)
 - }
 - }
 
運(yùn)行項(xiàng)目,點(diǎn)擊按鈕,效果和之前一致。
動(dòng)態(tài)增加 Params
GET 方法
GET 方法下,params 在經(jīng)過 url encode 之后直接附在 URL 末尾發(fā)送給服務(wù)器。修改 request() 方法,傳遞進(jìn)去一個(gè) params 的字典:
- static func request(method: String, url: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
 - ... ...
 - }
 
為了處理 params,我們從 Alamofire 偷來他的 params 處理函數(shù)。如果是 GET 方法,那就把處理過的 params 增加到 URL 后面。Network 類的完整代碼如下:
 
- class Network{
 - static func request(method: String, url: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
 - let session = NSURLSession.sharedSession()
 - var newURL = url
 - if method == "GET" {
 - newURL += "?" + Network().buildParams(params)
 - }
 - let request = NSMutableURLRequest(URL: NSURL(string: newURL)!)
 - request.HTTPMethod = method
 - let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
 - callback(data: data, response: response , error: error)
 - })
 - task.resume()
 - }
 - // 從 Alamofire 偷了三個(gè)函數(shù)
 - func buildParams(parameters: [String: AnyObject]) -> String {
 - var components: [(String, String)] = []
 - for key in sorted(Array(parameters.keys), [(String, String)] {
 - var components: [(String, String)] = []
 - if let dictionary = value as? [String: AnyObject] {
 - for (nestedKey, value) in dictionary {
 - components += queryComponents("\(key)[\(nestedKey)]", value)
 - }
 - } else if let array = value as? [AnyObject] {
 - for value in array {
 - components += queryComponents("\(key)", value)
 - }
 - } else {
 - components.extend([(escape(key), escape("\(value)"))])
 - }
 - return components
 - }
 - func escape(string: String) -> String {
 - let legalURLCharactersToBeEscaped: CFStringRef = ":&=;+!@#$()',*"
 - return CFURLCreateStringByAddingPercentEscapes(nil, string, nil, legalURLCharactersToBeEscaped, CFStringBuiltInEncodings.UTF8.rawValue) as String
 - }
 - }
 
修改前面的函數(shù)調(diào)用:
- @IBAction func mainButtonBeTapped(sender: AnyObject) {
 - Network.request("GET", url: "http://pitayaswift.sinaapp.com/pitaya.php", params: ["get": "Network"]) { (data, response, error) -> Void in
 - let string = NSString(data: data, encoding: NSUTF8StringEncoding)
 - println(string)
 - }
 - }
 
http://pitayaswift.sinaapp.com/pitaya.php 是我部署的用于測(cè)試的服務(wù)端代碼,會(huì)直接返回 ?get=ooxx 中的 ooxx。運(yùn)行項(xiàng)目,點(diǎn)擊按鈕,查看效果:
POST 方法
POST 方法下有幾個(gè)協(xié)議可供選擇,此處沒有文件上傳,我們采用較簡(jiǎn)單的 application/x-www-form-urlencoded 方式發(fā)送請(qǐng)求。request() 方法增加一些代碼:
- static func request(method: String, url: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
 - let session = NSURLSession.sharedSession()
 - var newURL = url
 - if method == "GET" {
 - newURL += "?" + Network().buildParams(params)
 - }
 - let request = NSMutableURLRequest(URL: NSURL(string: newURL)!)
 - request.HTTPMethod = method
 - if method == "POST" {
 - request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
 - request.HTTPBody = Network().buildParams(params).dataUsingEncoding(NSUTF8StringEncoding)
 - }
 - let task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
 - callback(data: data, response: response , error: error)
 - })
 - task.resume()
 - }
 
修改前面的函數(shù)調(diào)用:
- @IBAction func mainButtonBeTapped(sender: AnyObject) {
 - Network.request("POST", url: "http://pitayaswift.sinaapp.com/pitaya.php", params: ["post": "Network"]) { (data, response, error) -> Void in
 - let string = NSString(data: data, encoding: NSUTF8StringEncoding)
 - println(string)
 - }
 - }
 
使用 POST 方式發(fā)送請(qǐng)求,同樣服務(wù)端會(huì)返回 key 為 post 的 value 的值。運(yùn)行項(xiàng)目,點(diǎn)擊按鈕,結(jié)果和前面 GET 方法的結(jié)果一致。
至此,接口封裝完成!
















 
 
 










 
 
 
 