网络层的参考姿势

网络是任何一个系统/平台的基础功能,在iOS上也同样是这样的.从NSURLConnectionNSURLSession,从ASIHttpRequest到目前最主流的AFNetworking.

事实上,一个项目中通常会有一个更高层次的封装.可以是自行基于NSURLConnection进行封装,也可以基于AFNetworking或者Alamofire.

这里提供一个参考的姿势:ZCNetworking

结构

主要提供了3层

  1. 网络常用操作的抽象层:ZCNetworking,这里是基于AFNetworking
  2. 针对项目的具体操作Runner层:ZCApiRunner;提供大量的功能,配置以简化项目中的实际使用.
  3. Actions:普通/上传/下载操作的封装;包括参数/url等,也提供了一些便利操作,比如好用的log.

抽象层

这是比较重要的一层,将网络操作和具体实现隔离开来.仅仅暴露出一些task.

有了这一层,那么替换基础库就成为可能.ZCNetworking是基于AFNetworking,或许有一天会修改成其他的networking或者是直接使用NSURLSession呢?如果改动,只需要改动这一层即可,而整个项目不会受到任何影响.

这一层本身只提供几个基础方法:

  1. 数据获取: sendRequest
  2. 上传: uploadTask
  3. 下载:downloadFile;还包含了一个下载图片的方法
  4. 一些基础的操作方法,比如cookie等

基础方法中也提供了2种形式,以方便配置:包含NSURLSessionConfiguration和不包含.当然不包含则是默认.

暴露的接口较少,当然完全可以根据实际需求进行扩充.不过需要确定的一点就是:接口完全和任意第三方类无关.这样才能使得替换底层实现与上层无关.

接口的实现没有太多要注意的.按照正常的AFNetworking使用即可.

Runner

这一层是针对于项目的具体实现,做一些公共的配置/设置.包括:

  1. 区分正式/测试服务器
  2. 公共参数的处理,例如headers,params
  3. 对于逻辑成功/失败的处理
  4. 对于数据获取/上传/下载的处理
  5. 对于batch操作的处理
  6. 对于chain操作的处理
服务器区分

通常项目会有至少2个以上的服务器,正式和测试服务器.而对于服务器地址的管理,有多种方式.可以是纯手工的管理;可以是参数的配置,例如做一个宏;也可以做多个target;

纯手工当然不可取,太容易出错.好吧..说的就是我..的确因为疏忽翻过这样的错误.

配置本质上也是纯手工,只是设立了一个总开关.但是一旦疏忽,仍然有风险.

target会不会太heavy了点?假设还有cdn呢...

于是ZCNetworking中,根据当前环境来自行决定使用的服务器:

- (void)startWithDebugDomain:(NSString *)debug releaseDomain:(NSString *)release {
    _debugDomain = debug;
    _releaseDomain = release;
}

- (NSString *)currentDomain {
    if (_forceDomain.length > 0) {
        return _forceDomain;
    }
    else {
#ifdef DEBUG
        return _debugDomain;
#else
        return _releaseDomain;
#endif
    }
}

其中还增加了一个forceDomain,可以强制使用某个环境,这样便于调试.

公共参数

大多数项目会有这样的需求.例如我这里会为每一个请求中加上这样一组header:

headers[@"X-REQUESTED-WITH"] = @"1";

项目中也会需要公共参数,例如每条api需要版本号和平台等.

ZCNetworking在Runner中提供了相应的接口:addtionalHeadersglobleParams.

逻辑判定

基础网络只能够判定物理上是否成功.比如是否是http 200等.但是在很多时候,逻辑上的失败也是失败,应该进入failure流程,不应该进入success流程再进行判定.

例如登录操作.用户名密码错误然后返回.此时物理上成功(http 200),但是逻辑上失败.则应当进入失败流程.

对于一些公共错误,可能会有公共的操作方式.例如token/cookie过期导致登录失效,那么会弹出登录UI等.

所以会有几个操作:
codeKey/successCodes/warningCodes&&handler

codeKey则是返回字典的key

successCodes是个数组.如果返回字典的codekey字段的值满足successCodes,则认为逻辑成功,否则逻辑失败

warningCodes主要处理通用的错误,例如登录失效.handler当然就是处理的方式了.

是否逻辑成功完全依赖successCodes,和warningCodes无关.

不过这需要服务端提供类似的逻辑才行,如果提供不了,不设置即可.将不会对返回的逻辑状态进行处理,仅仅依赖物理状态.

请求的操作

一共就数据请求,上传,下载三大类.对应NSURLSessionDataTask/NSURLSessionUploadTask/NSURLSessionDownloadTask

利用之前的抽象层进行请求即可.不过请求内容已经被封装成Action类型.包括url,params等东西.

当物理状态返回后,根据配置对逻辑状态进行检查(不检查),最终返回相应的数据.

在请求中,有log是最方便的.以前关于调试,一般就2种方式:

  1. 断点
  2. 使用工具,例如charles.

不过断点不太方便,涉及到变量以及作用于的问题.针对个别问题还成,针对每一个请求都调试一翻,效率较低.

charles很好用,就是有点贵...

所以如果附带log信息的话,可能性价比较高.ZCNetworking提供了一些log信息:

  1. url和参数,以xxx.com/action?a=xx&b=xx的方式拼接,对于部分get请求可以直接用浏览器调用.
  2. method/header/params
  3. 对于error的log,包括物理和逻辑上的
  4. 返回值log,方便查看数据结构

log信息由action中的参数showLog来控制.

batch

不算特别常用的功能.但似乎也有点用.

例如在一个页面中,需要调用多条api才能将数据获取完毕,然后渲染界面.当然,这种方式显然不太好,加入某条api出错了呢?

在巧哥的YTKNetworking中也提供了同样的功能.使用一个count进行计数.当请求返回,则在返回中count++.当count等于请求的个数,则执行完毕.

ZCNetworking中,通过dispatch group处理这个功能.不过该功能有2个策略.
1.batch中一旦出错,立刻停止,返回错误.
2.batch中一旦出错,继续执行,最终返回一个字典.key为url,value为返回值.或许是object,或许是error.当然如果都成功,则返回字典.key为url,value为object.

ZCNetworking选择的是第一种策略.当然你也可以选择其他的策略.

chain

也不算特别常用的功能.也似乎有点用.

例如产品是必须先登录->在获取数据.

YTKNetworking类似于递归的感觉,通过next index计数,在请求完成后继续执行next,直到请求队列完毕.

ZCNetworking中使用semaphore来处理chain,不过遇上了一个坑.

信号量是一个简单的思路.类似于餐厅座位.有座位了就进入,没座位了就等待.进入后,座位少一张,出来后座位多一张,下个人才能进.

然而,在创建了一个信号量以后,使用AFHTTPSessionManager发送get请求居然没有反应!而使用NSURLSession却可以请求.

查找一番后,问题出现在了两个main thread死锁的地方.也就是信号量和AFHTTPSessionManager的默认complate queue.这个时候,手动设置complate queue即可:

manager.completionQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

返回值依然是一个字典,key为url.

当然会出现url相同的情况,这个时候key如何处理可以多斟酌一番,加上index?

more

需求的功能当然还可以有更多,例如巧哥提供了缓存,返回值验证,断点续传等
有必要的话完全可以继续扩展

Action(Model)

网络库的核心思路是把每一个请求封装成对象.所以每一个请求对应一个Action

请求有3种,action当然也就有3个.

  • ZCApiAction
  • ZCApiUploadAction
  • ZCApiDownloadAction

后2种继承自第一种.action中主要包含api的请求相关信息,例如url,params等.也包含一些api的控制信息,例如log开关.最后提供了2个回调,实现"插件机制":

typedef void (^ZCActionComplation) (BOOL isSuccess);
typedef void (^ZCVoidBlock) (void);

@property (nonatomic, copy)   ZCVoidBlock        actionWillInvokeBlock;
@property (nonatomic, copy)   ZCActionComplation actionDidInvokeBlock;

通过这两个回调,可以在一个请求之前,显示相应的hud,请求完毕后显示成功或者失败,然后去除.

在upload action中,需要支持单文件和多文件上传两种方式.所以提供了2组值(data/name/filename/mime):单个的形式(NSData和NSString)以及数组的形式.

使用

没有提供pod~~~可以把源文件拷贝,然后import "ZCApiLauncher.h"即可.

只是希望讨论一个恰当的方式,实际上每个团队都会自己维护一套适合自己的网络库.合适自己项目约定的才是最好的.

才疏学浅,有不对的地方请指正.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,099评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,358评论 6 343
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 11,612评论 4 59
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,293评论 18 399
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,200评论 0 17