自己动手写一个 iOS 网络请求库——降低耦合

移动开发 iOS 项目管理
现在的清汤挂面式的代码虽然便于理解,但是功能单一,代码杂乱。我们一起来分析 NSURLSession 的使用过程:

开源项目:Pitaya,适合大文件上传的 HTTP 请求库:https://github.com/johnlui/Pitaya

本文中,我们将一起降低之前代码的耦合度,并使用适配器模式实现一层独立于底层结构的网络 API,造一个真正的网络请求“库”。

降低耦合度

如何降低耦合度

现在的清汤挂面式的代码虽然便于理解,但是功能单一,代码杂乱。我们一起来分析 NSURLSession 的使用过程:

构造 NSURLRequest

确定 URL

确定 HTTP 方法(GET、POST 等)

添加特定的 HTTP 头

填充 HTTP Body

驱动 session.dataTaskWithRequest 方法,开始请求

具体实施

在 Network 下另外新建一个 NetworkManager 类,将 URL、params、files 等设为成员变量,让他们在构造函数中初始化:

  1. class NetworkManager { 
  2.  
  3. let method: String! 
  4. let params: Dictionary let callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void 
  5.  
  6. let session = NSURLSession.sharedSession() 
  7. let url: String! 
  8. var request: NSMutableURLRequest! 
  9. var task: NSURLSessionTask! 
  10.  
  11. init(url: String, method: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
  12. self.url = url 
  13. self.request = NSMutableURLRequest(URL: NSURL(string: url)!) 
  14. self.method = method 
  15. self.params = params 
  16. self.callback = callback 

之后,将上面分析的

1. 确定 URL

2. 确定 HTTP 方法(GET、POST 等)

3. 添加特定的 HTTP 头

4. 填充 HTTP Body

前三步封装到一个 function 中,***一步封装到一个 function 中,然后把驱动 session.dataTaskWithRequest 的代码封装到一个 function 中:
 

  1. func buildRequest() { 
  2. if self.method == "GET" && self.params.count > 0 { 
  3. self.request = NSMutableURLRequest(URL: NSURL(string: url + "?" + buildParams(self.params))!) 
  4.  
  5. request.HTTPMethod = self.method 
  6.  
  7. if self.params.count > 0 { 
  8. request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type"
  9. func buildBody() { 
  10. if self.params.count > 0 && self.method != "GET" { 
  11. request.HTTPBody = buildParams(self.params).nsdata 
  12. func fireTask() { 
  13. task = session.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in 
  14. self.callback(data: data, response: response, error: error) 
  15. }) 
  16. task.resume() 

之后使用一个统一的方法来驱动上面三个 function,完成请求:

  1. func fire() { 
  2. buildRequest() 
  3. buildBody() 
  4. fireTask() 

同时,不要忘了那三个 parse params 的从 Alamofire 偷来的函数哦,也要放到这个类里面。至此,降低耦合的工作基本完成,接下来我们开始封装“网络API”。

使用适配器模式封装“网络API”

理解适配器模式

适配器模式是设计模式中的一种,很容易理解:我的 APP 需要一个获取某一个 URL 返回的字符串的功能,我现在选择的是 Alamofire,但是正在发展的 Pitaya 看起来不错,我以后想替换成 Pitaya,所以我封装了一层我自己的网络接口,用来屏蔽底层细节,到时候只需要修改这个类,不需要再深入项目中改那么多接口调用了。

适配器模式听起来高大上,其实这是我们在日常编码中非常常用的设计模式。

Do it!

修改 Network 类的代码为:

  1. class Network{ 
  2. static func request(method: String, url: String, params: Dictionary = Dictionary(), callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
  3. let manager = NetworkManager(url: url, method: method, params: params, callback: callback) 
  4. manager.fire() 

搞定!

封装多级接口

不带 params 的接口:

  1. static func request(method: String, url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
  2. let manager = NetworkManager(url: url, method: method, callback: callback) 
  3. manager.fire() 

两个 get 接口(带与不带 params):
 

  1. static func get(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
  2. let manager = NetworkManager(url: url, method: "GET", callback: callback) 
  3. manager.fire() 
  4. static func get(url: String, params: Dictionary, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
  5. let manager = NetworkManager(url: url, method: "GET", params: params, callback: callback) 
  6. manager.fire() 

两个 post 接口(带与不带 params):
 

  1. static func post(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
  2. let manager = NetworkManager(url: url, method: "POST", callback: callback) 
  3. manager.fire() 
  4. static func post(url: String, params: Dictionary, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) { 
  5. let manager = NetworkManager(url: url, method: "POST", params: params, callback: callback) 
  6. manager.fire() 

测试接口

修改 ViewController 中的调用代码,测试多级 API:
 

  1. @IBAction func mainButtonBeTapped(sender: AnyObject) { 
  2. let url = "http://pitayaswift.sinaapp.com/pitaya.php" 
  3.  
  4. Network.post(url, callback: { (data, response, error) -> Void in 
  5. println("POST 1 请求成功"
  6. }) 
  7. Network.post(url, params: ["post""POST Network"], callback: { (data, response, error) -> Void in 
  8. let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String 
  9. println("POST 2 请求成功 " + string) 
  10. }) 
  11.  
  12. Network.get(url, callback: { (data, response, error) -> Void in 
  13. println("GET 1 请求成功"
  14. }) 
  15. Network.get(url, params: ["get""POST Network"], callback: { (data, response, error) -> Void in 
  16. let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String 
  17. println("GET 2 请求成功 " + string) 
  18. }) 
  19.  
  20. Network.request("GET", url: url, params: ["get""Request Network"]) { (data, response, error) -> Void in 
  21. let string = NSString(data: data, encoding: NSUTF8StringEncoding) as! String 
  22. println("Request 请求成功 " + string) 

运行项目,点击按钮,查看效果:

 

多级 API 封装成功!
 

责任编辑:chenqingxiang 来源: 吕文翰_JohnLui 的博客
相关推荐

2015-06-02 09:51:40

iOS网络请求封装接口

2015-06-02 09:41:00

iOS网络请求NSURLSessio

2017-03-02 13:31:02

监控系统

2023-12-16 13:21:00

Python元类ORM

2020-09-29 12:13:46

SQL引擎底层

2017-02-14 10:20:43

Java Class解析器

2023-12-15 10:14:42

数据库select语句

2014-11-26 10:54:20

C#

2021-02-22 17:17:38

Proxy缓存代码

2015-07-23 14:53:50

贝叶斯分类器

2021-07-04 10:07:04

Virtual DO阅读源码虚拟DOM

2018-04-08 11:20:43

深度学习

2024-03-08 12:45:00

C#Web服务器

2018-02-07 10:46:20

数据存储

2018-09-12 10:58:11

NBA数据存储

2021-04-26 07:31:22

SpringMVCweb框架

2022-08-29 14:22:03

bpmn.jsVue流程

2012-07-30 09:40:52

Lua

2022-03-09 09:43:01

工具类线程项目

2019-03-21 09:45:20

IM即时通讯CIM
点赞
收藏

51CTO技术栈公众号