学习笔记 - iOS 应用架构谈_网络层设计方案

非常感谢Casa老师的文章,让我长久以来的很多疑惑,很多看了又忘的知识得到了系统的整理和总结。文章很容易让我建立起自己的记忆模型。就我的感觉,作为iOS程序员,把这样的文章读上几十遍都不为过,有种醍醐灌顶的痛彻。其中还有一个很重要的点,作为架构师是为工程师服务的,这种想法尤其的纯粹,放到工程师身上,如果也想着自己的代码是给别人读的,自己的产品是给用户用的,相信世界将变得更美好,我们离梦想也会更近。

使用哪种交互模式来跟业务层做对接?  --  什么方式,什么样的数据

是否有必要将API返回的数据封装成对象然后再交付给业务层?

使用集约化调用方式还是离散型调用方式去调用API?

针对链接建立环节的优化

针对链接传输数据量的优化

针对链接复用的优化


1. 网络层跟业务对接部分的设计


1)使用哪种交互模式对接?

<1> 什么方式交付数据

-  主delegate,辅Notification(当需求要求跨层时,如网络条件切换)

分层架构的目的其中之一就在于下层对上层有一次抽象,让上层可以不必关心下层而执行自己的业务。


-  网络层然后尽量不要用block

(1)block很难追踪,难以维护

     block()  // 根本不知道这个block干了什么

(2)block会延长相关对象的生命周期

     潜在的retain cycle,延长生命周期

平时尽量不要滥用block,尤其是网络层。


统一回调方法,便于调试和维护

block无法做到回调方法的统一,调试和维护的时候也很难在调用栈上显示出来,找的时候会很蛋疼。

网络请求和网络层接受请求的地方时,使用block没问题。但是在获得数据交给业务方时,最好还是通过delegate去通知到业务方。因为block所包含的回调代码跟调用逻辑在同一个地方,会导致那部分代码变得很长,因为这里面包括了调用前&后的逻辑。从另一个角度来说,在一定程度上违背了single function,single task的原则,在需要调用API的地方,就只要写API调用相关的代码,在回调的地方写回调的代码。

Block是目前大部分第三方网络库都采用的方式,因为在发送请求的那一部分,使用Block能够比较简洁,因此在请求那一层是没问题的。只是在交换数据之后,转变成delegate比较好。

尽可能通过Delegate回调方式交付数据,这样可以避免不必要的跨层访问。当出现跨层访问的需求时(比如信号类型切换),通过Notification的方式交付数据。正常情况下应该避免使用Block。


<2> 交付什么样的数据给业务层?

很多拿到JSON会转变成对象模型

reformer过滤  --  是对数据转化逻辑的一个封装

-- 保持NSDictionary数据可读性

NSString *const kPropertyListDataKeyID  = @"kPropertyListDataKeyID";

设计初衷:通过reformer转换出来的可以直接是View,或者是view直接可以使用的对象(包括NSDictionary)。


总结:View + APIManager = reformer,NSDict + const字符串key

对于业务层而言,由Controller根据ViewAPIManager之间的关系,选择合适的reformer将View可以直接使用的数据(甚至reformer可以用来直接生成View)转换好之后交付给View。对于网络层而言,只需要保持住原始数据即可,不需要主动转化成数据原型。然后数据采用NSDictionary + Const字符串key 来表征,避免了使用对象来表征带来的迁移困难,同时不失去可读性。


(2)集约型 和 离散型 API调用方式?

<1> 集约型API,就是所有API调用只有一个类,这个类接收API名字,API参数和回调着陆点作为参数。

[APIRequest  startReqWithApiName:@"name"   params:params  success:@selector(success:)  fail:@selector(fail:)  target:self];

<2> 离散型API,一个API对应一个APIManager,只要参数。API名字、着陆点都集成在APIManager中。

@property  (nonatomic, strong)  ItemListAPIManager  *itemListAPIManager;

// getter方法初始化

[self.itemListAPIManager  loadDataWithParams:params];

<3> 单看下层,都是集约型。因为发起一个API请求之后,除了业务相关(参数和API名字),剩下的都是统一处理的:加密,URL拼接,API请求的起飞和着陆。


业务层代码用离散型:

<1> 当前请求在外飞,不同业务需求有两种请求起飞策略:<1> 取消新发起的请求,等待外面飞的请求着陆(刷新页面的请求,刷新详情,刷新列表)。<2> 取消外面飞的请求,新发起的请求起飞(列表筛选,商品类型,价格区间)。---  对于离散型API,编写不同的APIManager时候就可以针对不同的API设置不同的起飞策略。

<2> 便于针对某个API请求来进行AOP

<3> API请求的着陆点消失时,离散型能更好的处理

--- 页面的请求在外飞,用户点了back,然后VC被pop被回收。请求的着陆点就没了。容易crash。一般来说,处理这个情况都是在dealloc的时候取消当前页面所有的请求。(集约型)          但离散型可以写到APIManager里面。


总结:

对外提供一个BaseAPIManager来给业务方做派生,在BaseManager里面采用集约化的手段组装请求,放飞请求,然而业务方调用API时,以离散型调用。

如何做继承?

在APIManager情况下,最直觉就是BaseAPIManager提供一些空方法给子类重载。不好。可以用IOP来限制派生类的重载。

self.child = self;   OR   NSAssert(NO, "ERROR");

[self  requestWithAPIName:[self.child  apiMethodName] ...];

这么做好处是避免父类写空方法,约束子类。业务方实现子类,可以根据Protocol方法实现。


网络层与业务层对接总结:

(1) delegate数据连接,Notification跨层访问

(2) NSDictionary --> 业务层,用const字符串作Key保持可读性

(3) reformer处理网络层反馈数据

(4) 网络层上部分用离散型,下部分集约型

(5) 设计合理的继承机制,使派生APIManager受到限制


2. 网络层安全机制


(1)判断API调用请求来自于经过授权的APP

<1> 确保调用来自自己的APP,防止爬

设计签名:服务端给密钥,每次调用API时,使用,密钥+API名字+API请求参数 = hash,服务端按照相同方法生成比较。增加hash复杂度 = MD5...

<2> 对外提供需要注册才能使用的API平台,识别注册用户调用

较复杂,不做记忆


(2) 保证传输数据的安全

<1> 防止中间人攻击

<2> SPDY与HTTPS

HTTP/HTTPS  SPDY 链接复用


3. 网络层的优化方案


(1)针对链接建立环节的优化

<1> 发起请求

--  使用缓存手段减少请求的发起次数

什么时候清理缓存? 根据超时和缓存数据的大小

请求 -- 内存 -- 本地存储 --  再发起请求


--  策略减少请求的发起次数

i. 取消策略

刷新界面的请求和条件筛选的请求

ii. 用户日志的请求策略

在本地记录用户的操作记录,记录满30条发起一次请求将操作记录上传到服务器,然后,每次App启动的时候,上传一次上次遗留的没上传的记录。


<2> DNS域名解析得到IP

根据IP进行三次握手,链接建立成功

直接走IP请求,绕过DNS服务,尽可能不要用户使用对他来说很慢的IP方案为本地有一份IP列表,这些IP是所有提供API的服务器IP,每次app启动的时候,针对这个列表里的所有IP取ping延迟,选择最小的…

应用启动获取本地所有IP的ping,通过NSURLProtocol将URL中的HOST修改为我们找到的最快的IP


(2)针对链接传输数据量的优化

各种压缩


(3)针对链接复用的优化

SPDY  &  PipLine

维护一个队列

twitter-CocoaSPDY    Voxer/iSPDY

有网络库的代码  PPT

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

推荐阅读更多精彩内容