吕文翰 php,自己动手写一个 iOS 网络请求库(三)——降低耦合
自己动手写一个 iOS 网络请求库(三)——降低耦合
2015-5-22 / 阅读数:16112 / 分类: iOS & Swift
本文中,我们将一起降低之前代码的耦合度,并使用适配器模式实现一层独立于底层结构的网络 API,造一个真正的网络请求“库”。
降低耦合度
如何降低耦合度
现在的清汤挂面式的代码虽然便于理解,但是功能单一,代码杂乱。我们一起来分析 NSURLSession 的使用过程:构造 NSURLRequest
确定 URL
确定 HTTP 方法(GET、POST 等)
添加特定的 HTTP 头
填充 HTTP Body
驱动 session.dataTaskWithRequest 方法,开始请求
具体实施
在 Network 下另外新建一个 NetworkManager 类,将 URL、params、files 等设为成员变量,让他们在构造函数中初始化: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
前三步封装到一个 function 中,最后一步封装到一个 function 中,然后把驱动 session.dataTaskWithRequest 的代码封装到一个 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()
}
之后使用一个统一的方法来驱动上面三个 function,完成请求:func fire() {
buildRequest()
buildBody()
fireTask()
}
至此,降低耦合的工作基本完成,接下来我们开始封装“网络API”。
使用适配器模式封装“网络API”
理解适配器模式
适配器模式是设计模式中的一种,很容易理解:我的 APP 需要一个获取某一个 URL 返回的字符串的功能,我现在选择的是 Alamofire,但是正在发展的 Pitaya 看起来不错,我以后想替换成 Pitaya,所以我封装了一层我自己的网络接口,用来屏蔽底层细节,到时候只需要修改这个类,不需要再深入项目中改那么多接口调用了。
适配器模式听起来高大上,其实这是我们在日常编码中非常常用的设计模式。
Do it!
修改 Network 类的代码为: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()
}
}
搞定!
封装多级接口
不带 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()
}
两个 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()
}
两个 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()
}
测试接口
修改 ViewController 中的调用代码,测试多级 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 请求成功")
})
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 请求成功 " + string)
})
Network.get(url, callback: { (data, response, error) -> Void in
println("GET 1 请求成功")
})
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 请求成功 " + 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 请求成功 " + string)
}
}
运行项目,点击按钮,查看效果:
多级 API 封装成功!
WRITTEN BY
程序员,Swift Contributor,正在写《iOS 可视化编程与 Auto Layout》。
评论:
iOSQiao
2016-04-27 15:33
我这样使用会报错:
Network.request("GET", url: "http://192.168.1.111/network.php") { (data, response, error) -> Void in
let string = NSString(data: data!, encoding: NSUTF8StringEncoding)
print(string)
}
错误提示: Ambiguous use of 'request(_:url:callback:)'
加上params就行,请问博主,这是为什么?
KangKai
2015-10-01 19:39
吕老师,我想请问下,以get方法为例,不知道这样写是不是更简洁,还是说你那样写有别的考虑?
//两个 get 接口(带与不带 params)
static func get(url: String, callback: (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void) {
self.get(url, params: Dictionary(), callback: callback)
}
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()
}
2015-10-01 22:39
@KangKai:当时这么写是因为 Swift 编译器的代码提示工具做的还不是很好,现在直接给参数设置默认值,在代码提示里就会直接显示两个 api 了。
那爱离殇
2015-06-02 13:34
本人对封装网络库有一个疑问,就是要不要在封装的API里面加上网络请求的风火轮以及错误信息抛出?如果不加的话,那要在每个用到的地方都要加,如果加上的话,可能个别地方又不需要加!请指教^_^
2015-06-02 15:23
@那爱离殇:网络库只是一个底层库,只完成一件事。对于具体的业务,上层是可以再封装的。UI 上的菊花会动和错误信息抛出建议每个接口都单独处理。
那爱离殇
2015-06-02 15:30
@JohnLui:
那简直让人崩溃呀,每个地方都写!!!
2015-06-02 15:54
@那爱离殇:业务需要嘛
cclv
2015-05-31 21:31
小弟遇到了一个问题:
报错:
ambiguous use of 'post'
ambiguous use of 'get'
下边这俩方法
Network.post(url, callback: { (data, response, error) -> Void in
println("POST 1 请求成功")
})
Network.get(url, callback: { (data, response, error) -> Void in
println("GET 1 请求成功")
})
2015-05-31 21:43
@cclv:目测是因为:
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()
}
写成了一样的参数,其实是不一样的。
发表评论:
昵称
邮件地址 (选填)
个人主页 (选填)
吕文翰 php,自己动手写一个 iOS 网络请求库(三)——降低耦合相关推荐
- 写一个nodejs 网络请求
我可以给你一个简单的nodejs网络请求的例子: const http = require('http'); const req = http.request({ hostname: 'example ...
- 吕文翰 php,自己动手打造基于 WKWebView 的混合开发框架(二)——js 向 Native 一句话传值并反射出 Swift 对象执行指定函数...
自己动手打造基于 WKWebView 的混合开发框架(二)--js 向 Native 一句话传值并反射出 Swift 对象执行指定函数 2015-9-2 / 阅读数:39757 / 分类: iOS & ...
- 自己动手写一个印钞机 第四章
2019独角兽企业重金招聘Python工程师标准>>> 作者:阿布? 未经本人允许禁止转载 ipython notebook git版本 目录章节地址: 自己动手写一个印钞机 第一章 ...
- 自己动手写一个印钞机 第二章
2019独角兽企业重金招聘Python工程师标准>>> 作者:阿布? 未经本人允许禁止转载 ipython notebook git版本 目录章节地址: 自己动手写一个印钞机 第一章 ...
- 自己动手写一个印钞机 第一章
2019独角兽企业重金招聘Python工程师标准>>> 作者:阿布? 未经本人允许禁止转载 ipython notebook git版本 目录章节地址: 自己动手写一个印钞机 第一章 ...
- 小飞鱼通达二开 软件版权登记之自己动手写一个源代码文档生成器(图文)
软件开发过后,如果需要对软件进行保护就需要进行版权登记,现在登记都可以在网上进行也是非常的方便,在版权登记网站登记信息后,需要打印一份表格签字,然后就是需要准备软件的设计说明书和打印源代码2个事情. ...
- 自己动手写一个推荐系统,推荐系统小结,推荐系统:总体介绍、推荐算法、性能比较, 漫谈“推荐系统”, 浅谈矩阵分解在推荐系统中的应用...
自己动手写一个推荐系统 废话: 最近朋友在学习推荐系统相关,说是实现完整的推荐系统,于是我们三不之一会有一些讨论和推导,想想索性整理出来. 在文中主要以工程中做推荐系统的流程着手,穿插一些经验之谈,并 ...
- 自己动手写一个仿Docker虚拟容器
自己动手写一个仿Docker虚拟容器 本项目参照书籍<自己动手写Docker> 作者:陈显鹭(花名:遥鹭)-阿里云高级研发工程师等 项目地址:https://gitee.com/Sheng ...
- java 手编线程池_死磕 java线程系列之自己动手写一个线程池
欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. (手机横屏看源码更方便) 问题 (1)自己动手写一个线程池需要考虑哪些因素? (2)自己动手写 ...
最新文章
- 日志系统新贵Loki,确实比笨重的ELK轻
- 题目1024:畅通工程
- word 另存为xml后,读取xml的图片数据
- C++ Primer 5th笔记(chap 16 模板和泛型编程)转发参数包
- ubuntu14.04管理员密码忘记的解决方法
- ASCII表完整版(包含16进制对应表)
- 2020蓝桥杯省赛---java---B---6(分类计数)
- 向量积 和 它的计算_7
- 羡慕,浙江大学的双 11 快递,全部由物流机器人配送
- Android 广播接收器注册与注销源码分析
- cactiez v11使用配置mysql_cactiez应用监控部署手册.doc
- 解释Spring中IOC, DI, AOP
- Atitit.javascript 实现类的方式原理大总结
- C++标准委员会7月科隆会议中投票通过的特性
- html如何在搜索栏里加放大镜,css 如何在html页面上输出一个“放大镜”形状呢?...
- Cryengine5.3
- Java学习1——计算机基础知识
- 福莱特法公式matlab,浙江省公路出行交通分布模型研究
- ecshop mysql 报错_修复ecshop数据库ecs_sessions.MYI报错
- 撰写论文时常用的研究方法有哪些?