Swift 轻量级网络层设计
前言
普遍我们的网络层设计的时候直接是如下结构APIManager.post(url, parameter,completeHandle),服务器配置在APIManager.m文件中进行配置。这样一个简单便捷网络请求类便写好了,但细心思考我们会发现如下一些问题:
相同API可能分散各处导致每次需要填写的参数key值。回调处理代码也可能会存在冗余。
//例如登录功能 APIManager.post("登录APIUrl",{"name":"","pwd":""},completeHandle)
//登录功能首先必然存在于LoginVc中
LoginVC ==> 登录功能
//此时要求实现自动登录功能,那么在主控制器生成时应该判断是否可以自动登录(当然也可以推出LoginVc后再去自动登录)
MainVc ==> 自动登录(登录功能)
此时便需要在两处来写入url、parameter及回调方法,当此接口有更新时就需要在两处进行修改,若工程中用到的此网络功能越多则需要修改的地方也越多!
部分网络请求需要随着页面的pop而取消,手动进行管理task显得笨拙而麻烦。
关于网络请求起飞后回调没有着陆点是很危险的一件事,因此正常的做法是让APIManager.post返回task任务,并有当前请求发起类持有,并在当前请求类析构并且task任务未完成时取消。这样的操作方式一看就繁琐,若一个大工程处处这样维护怕是相当麻烦了!
因此我们便需要设计出一个能解决上述问题的网络层设计
设计模式

此种设计主要是请求类持有自定义Request,并向中间件BQAPIManager传入Request调用URLSession。此过程中Request会持有task任务,当请求类被释放时,Request也会释放,此时判断其是否有任务执行如有任务执行则停止执行。从而达到自动取消任务的功能。而此时针对相同的url及其参数便可封装与一个Request中,可有效的减少冗余代码!
关键类说明
BQRequest.Swift
主要在于封装参数key值和设定url并处理网络请求类容及持有并按需取消或释放task任务
//关键代码如下
var method: HTTPMethod = .post
var result: Any?//如成功处理网络请求内容后result有值
weak var task: URLSessionTask?
public func url() -> String { return "" }//API接口
//模型转字典
public func toDiction() -> [String: Any] {
let mir = Mirror(reflecting: self)
var dict = [String: AnyObject]()
for p in mir.children {
if p.label == "method" || p.label == "result" || p.label == "task"{
continue
}
dict[p.label!] = (p.value as AnyObject)
}
return dict
}
//请求内容处理
public func responseAction(data: Data?, response: URLResponse?, error: Error?) {
if let data = data {
do {
self.result = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
} catch let err as NSError {
print(err.localizedDescription)
}
}
if let error = error {
print(error.localizedDescription)
}
}
//保证析构时(请求类不存在时)取消正在执行的任务
deinit {
if let task = self.task{
if task.state == .running || task.state == .suspended {
print("cancel \(task)")
task.cancel()
}
self.task = nil
}
}
BQAPIManager.Swift
主要作用为配置服务器环境(方便本地、测试服、正式服的切换),并通过传入的Request发起网络请求。
其中主要的关键点在与避免Request与task的循环持有。
//关键代码如下
public class func sendRequest(request: BQRequest, completionHandler:@escaping () -> ()) {
weak var req = request
let task = BQNetWork.sendRequest(urlstr: baseUrl + request.url(), parameter: request.toDiction(), method: request.method, time: 10, headers: nil) { (data, response, error) in
//对返回内容进行处理,如果处理成功结果赋予Request.result之中
req?.responseAction(data: data, response: response, error: error)
DispatchQueue.main.async {
if req?.task != nil {
completionHandler()
//任务完成后释放task任务
req?.result = nil//此处最好让网络调用类来决定是否置空result
req?.task = nil
}
}
}
request.task = task
}
其中BQNetWork中的内容是基于URLSession的一个简单封装,这里便不再详述
使用方式
以上述登录功能为示例,此时需设计LoginRequest继承与BQRequest并重写其url 及 responseAction方法
public name: String?
public pwd: String?
override public func url() -> String { return "登录APIUrl" }
override public func responseAction(data: Data?, response: URLResponse?, error: Error?) {
super.responseAction(data: data, response: response, error:error);
if let result = self.result {
//登录处理通用功能实现
}
}
接着让LoginVc持有LoginRequest对name及pwd赋值(减少因参数key字段出错而失败的情况),并通过BQAPIManager发起请求即可。
后记
这种设计方式主要是通过对Moya的模仿变化而来,其做到了最简单、方便的管理。当然在实际运用中可能也会出现问题,如发现问题或有何不妥之处望指正!谢谢!最后附上笔者自己的Swift工具库
Swift 轻量级网络层设计的更多相关文章
- 【转】Swift 语言的设计错误
Swift 语言的设计错误 在『编程的智慧』一文中,我分析和肯定了 Swift 语言的 optional type 设计,但这并不等于 Swift 语言的整体设计是完美没有问题的.其实 Swift 1 ...
- iOS网络层设计感想
App的开发无外乎从网络端获取数据显示在屏幕上,数据做些缓存或者持久化,所以网络层极为重要.原来只是把AFNetwork二次封装了一下,使得调用变得很简单,并没有深层次的考虑一些问题. 前言 参考: ...
- Swift 路由机制设计
设计模式 APP设计模式多种多样,从最初的MVC到MVVM,再到MVP,VIPER等.越来越多的设计模式被开发出来并得以应用,但不论我们用到哪种设计模式,只需要记住高内聚.低耦合那边是好的设计模式.在 ...
- Swift基础之设计折线坐标图
最近添加了折线视图的样式,所以在这里用Swift语言重新再使用设计一下 首先设置纵坐标的数值是:体重 //体重 let weightLabel = UILabel.init(frame: ...
- 轻量级RPC设计与实现第五版(最终版)
在最近一段时间里,通过搜集有关资料加上自己的理解,设计了一款轻量级RPC,起了一个名字lightWeightRPC.它拥有一个RPC常见的基本功能.主要功能和特点如下: 利用Spring实现依赖注入与 ...
- 轻量级RPC设计与实现第三版
在前两个版本中,每次发起请求一次就新建一个netty的channel连接,如果在高并发情况下就会造成资源的浪费,这时实现异步请求就十分重要,当有多个请求线程时,需要设计一个线程池来进行管理.除此之外, ...
- Kafka Broker源码:网络层设计
一.整体架构 1.1 核心逻辑 1个Acceptor线程+N个Processor线程(network.threads)+M个Request Handle线程(io threads) 多线程多React ...
- Swift - 让StoryBoard设计视图,程序运行时都使用横屏形式
1,运行时横屏 将项目属性“General”->“DeviceOritentation”的Portrait复选框去掉 2,storyboard设计视图横屏 在storyboard中,单击中间界面 ...
- 轻量级RPC设计与实现第四版
在本版本中引入了SPI机制,关于Java的SPI机制与Dubbo的SPI机制在以前的文章中介绍过. 传送门:Dubbo的SPI机制与JDK机制的不同及原理分析 因为设计的RPC框架是基于Spring的 ...
随机推荐
- 关于Eclipse+SVN 开发配置
入职快一个月,学的比较慢,但学的东西很多,受益匪浅.有时候真正意义上,感受到:代码使我快乐,我爱编程. 好久没有开笔,不知道说些什么,也不知道应该说什么. 但总觉得有些东西,很想说出来,不用理会他人的 ...
- Unity与Android交互-Unity接入高德地图实现定位以及搜索周边的功能(使用Android Studio)详细操作
刚进公司给安排的任务就是Unity接入高德地图,算是踩了不少坑总算做出来了,抽点时间写个博客记录一下 废话不多说 先上效果图 获取定位并根据手机朝向显示周边信息 使用的Unity ...
- php实现ppt转图片,php调用com组件问题
PHP 调用com组件将ppt转为图片. 需要在php.ini中开启 extension=php_com_dotnet.dllcom.allow_dcom = true 测试代码如下: < ...
- forfiles命令批处理删除过期文件
命令格式: forfiles.exe /p "D:\备份" /s /m *.zip /d -7 /c "cmd /c del @path" /p:指定目录 /s ...
- 通过 itms:services://? 在线安装ipa ,跨过app-store
1.需要一个html文件,引导下载用户在线安装ipa <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN&quo ...
- 大话Python中*args和**kargs的使用
对于初学者来说,看到*args和**kargs就头大,到底它们有何用处,怎么使用?这篇文章将为你揭开可变参数的神秘面纱 1.*args 实质就是将函数传入的参数,存储在元组类型的变量args当中 de ...
- Java学习笔记--动态代理
动态代理 1.JDK动态代理 JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy ...
- 文件存储B+树
文件存储要选用B+树这样的数据结构 “文件存储要选用B+树这样的数据结构”——没记错的话,这是严蔚敏那本数据结构书上的一句结论.不知道是我没细看还是她没细讲,反正当时纯粹应试地记了这么个结论.不求甚解 ...
- 【Android Developers Training】 104. 接受地点更新
注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...
- Linux编程之epoll
现在有这么一个场景:我是一个很忙的大老板,我有100个手机,手机来信息了,我的秘书就会告诉我"老板,你的手机来信息了."我很生气,我的秘书就是这样子,每次手机来信息就只告诉我来信息 ...