16年的时候写过一篇代码讲解的,依旧是这三种架构,现在20年将近了,看到好的文章,是否增加新的认识。

16年链接

iOS - 架构模式 - 解密 MVC、MVP、MVVM、VIPER架构

新项目选择架构

MVC

MVP

MVVM

VIPER

mvc不说大家常用的方式,VC解决一切。mvp来自于微软的面像协议编程,mvvm想必用过阿里前端库VUE的都了解。viper美团设计一种的架构模式

但是时间紧,公司貌似不重视此方面的技术。认为一切都可以在一俩个月内解决所有问题,出一个完整的项目,对此我也是很无语。

在此也就是重温一下常用架构模式。最终我选择自定义框架。大量的引用组件和第三方资源库来解决燃眉之急。之后准备悬崖勒马了。

iOS架构的认识过程 经典就是经典,没有之一。iOS中MVC架构,看懂斯坦福大学⽩胡子老头这张图基本上就可以了

简单理解,就是Controller对象拥有View和Model对象,两者通过Controller进行沟通。对于单个⻚页面,三个类就搞定了,感觉很简单。

MVC

网络连接应该放在哪里?Model中吗?感觉很有道理?实际上,很多的网络连接的发起和接收后 的处理都放在了Controller中,因为方便嘛。Model一般只有属性定义,没有实现。

View应该是独⽴一块了了吧?实际上呢,View大多都放在了Controller中,有个loadView函数,很⽅便啊。有几个人会单独写个类来作为view?

本来,xib和Storyboard是很好的分离view的⽅方式。但是,由于“不合适多⼈合作,版本管理”,⾮要代码写界面,还振振有词:“性能⾼,对培养新人有好处”。“谎言说100次都能成真话”,何况这些理由听上去还那么有理。

像“检查⽤户名是否合法,检查密码对不对”应该放在哪里呢?有几个人会像斯坦福大学白胡子老头那样新起一个类来写?基本上都是Controller中搞定。

BaseController,BaseView,BaseModel一定⻅过不不少吧?有的还有好几层呢 公共View,各种名字带common或者类似的类常见吧?里面⽹络连接,数据库,逻辑等往往比

View本身很多,俨然一个⼩小模块了了,功能比Controller都强大了。这还是view吗? 本来MVC理论上是最简单的架构,但是实际结果呢,变成了最难懂的架构。Controller成了上帝

类,什么都干。“只知道那一坨东⻄有用,但看不出那是简单的MVC”。

MVC也被称之为 Massive View Controller(重量级视图控制器器)。其实这不是MVC的错,只是没 有程序员承认自己懒惰,编程习惯不好罢了了。如果能够像斯坦福⼤学⽩胡⼦老爷爷那样好的编程习 惯,那么大部分的iOS程序都能有清晰的MVC架构。

MVVM

MVVM来⾃自MVC,⼀一张经典的图就是下⾯面这张,在好多文章中看到过。

 
 

“稍微考虑一下,虽然 View 和 View Controller 是技术上不同的组件,但它们几乎总是手牵手在一 起,成对的。你什么时候看到一个 View 能够与不同 View Controller 配对?或者反过来?所以,为什么不正规化它们的连接呢?” ------ 这段话当时给我的印象很深刻,这个观点到现在我都认可。

Controller代表了一个场景(Scene)的⽣生命周期,是一个调度者。什么都是,因为什么都离不开 它。又好像什么都不是,因为它代表不了任何具体的东⻄西。让它和View合在一起,作为广义的view 就有了了具体的意义,并限制了它无所不能的印象。这点值得肯定。

“显示逻辑(presentation logic)”可以从Controller中移到ViewModel中,从而给Controller减负。 这个观点我也是支持的。并且我以此认为ViewModel就是用来做“显示逻辑”的,一个页面一个,随⻚面而变化。在Swift中,我用结构体来做ViewModel。

关于绑定机制,文章中推荐ReactiveCocoa。我去⼤致看了一下,主要是将KVO,Block,notification,delegate等各种通讯机制统一为RACSignal,将界面和数据进行双向绑定,功能确实强大。但是这个风格和普通iOS的开发习惯差距⽐较大,一下子很难变过来。文章中也说只是推荐,不 强求,所以我也就一直没有采用。被误解的MVC和被神化的MVVM

至于绑定机制,在Swift中可以使用属性观察者。ViewModel一般作为Controller的⼀个属性,对它 进行观察,一旦变化,就⽤用ViewModel新的值设置界面元素,感觉挺好用的。还有一些相隔很远或 者一对多的变化,一般可以采用NSNotification来达到目的。

从网络取数据,业务逻辑(相对于显示逻辑),应该放在那里呢?文章中没有说,看意思是保留 在Controller中。还有的观点认为应该放在ViewModel中,这当然有道理,而且这是主流的理解。但 是这样会让ViewModel变成另外一个上帝类。

我理解的MVVM

这是本⼈的理解,仅仅一家之言。主流的观点没有Logic那个类,从图中删除基本上就是了。 ViewModel将是替代Controller的⼀个上帝类。

Controller主要作为调度者,居于中心位置。客串串部分View相关功能:比如动画⾥面关于view的位 置改变,这些代码是要放在Controller里面的。这也符合Controller+View实现view功能的概念。

ViewModel专⻔门做“显示逻辑”,并且用属性观察者做绑定,必要的时候用Notification。正向的绑定 比如“action-target”响应就保留留在Controller中,具体事情交个其他类做就可以了。

在Swift中,ViewModel和Model推荐用Struct;Logic倾向于用class。从一个简单直观的概念来 说,ViewModel需要保持轻量级,跟随⻚面走,随时准备修改。Model也是轻量量级,跟随后台API定 义走,只是个数据结构,随时准备修改。⽽而Logic就显得比较大,考虑稳定,考虑复用。

增加Logic类,负责业务逻辑,比如从⽹络取数据,修改数据库,检查⽤户名合法性,具体的响应 逻辑,监听后的具体处理等

重点是Controller减负,尽量起调度者职能,具体工作都放到Logic中处理理。

Logic考虑复用,可以对应单个⻚面,也可以多个⻚面共用。按照业务逻辑的思路路去划分模块。划 分标准可以和⻚面分类标准不一样。

对于复杂⻚面,View和ViewModel可以多个,按照组件的模式去考虑。

对于表格,ViewModel对应的是表格的cell,dataSource数组中放ViewModel的序列。

表格的delegate和dataSource,⽬前来看,放在Controller中是最⽅便的。当然,为了给Controller 减负,再新增一个类TableDelegate也是很不错的方法。

如果表格包含在一个组件中,⽤用容器器view做delegate和dataSource是一个不错的选择。 主要想法就是想方设法“架空”Controller,让它只做一个调度者,管理⻚面的⽣命周期就可以了了。

实在非它不可的时候,才让它做具体的事情。

不引入ReactiveCocoa等庞大的第三方库。这⾥里里有一篇文章不错,值得学习一下。ReactiveCocoa 和 MVVM 入门

VIPER 这是比MVVM分类更更细的一种模式。

View: 也是View + Controller
Present:相当于ViewModel,叫展示器器 Interactor:交互器器,侧重于业务逻辑;从网络取数据,数据库等功能都在这里。 Entity:就是Model,仅仅是数据定义
WireFrame:就是Router,是⻚面跳转

值得借鉴的地⽅方

将⻚页⾯面跳转独立出来,做成公共模块

将业务逻辑独立出来,做成公共模块

如果只是对于单个页面,分这么多类,感觉有点啰嗦了。不不够对于多⻚面的模块来说,还是有借鉴意义的

其他架构

一些实际在用,但是没有通用缩写名称的架构 分层模式

将服务service的概念引入客户端,作为一个中间层,进⾏隔离 业务逻辑作为服务模块,通过服务的方式进行访问 数据访问跟业务逻辑,表现层分开,是跟后台的接口层

表现层只关注UI,相当于VIPER中的V和P;或者是MVVM中的ViewModel(仅显示逻辑)和 View,但是没有双向绑定;

平台模式

当前的APP,大多数是Native和H5的混合,将两者的接口代码统一成通用模块是比较好的做法 插件化也是一个越来越普遍的趋势,比如分享,第三方登录,支付等等,都由第三方以插件的形

式提供。对这些插件集中管理也是好的做法

APP随着公司发展壮大,分出不不同的事业部,在同一公司多个APP或者不同业务;这样就有两个 相反的发展趋势:一方面,想共用模块,让多个业务共享;另一方面,各⾃业务又要隔离,独立发展。公司也有可能成立公共的平台部。各业务部⻔之间是纵向拆分;业务和平台之间是横向拆分。 这就导致二维划分的立体架构。

Step0:平台型应用

以URL的⽅式,由主App调⽤子App 形式类似于调用打电话,发短信,发邮件 ,URL的定义需要统筹考虑

Step1:纵向划分

分Native,H5,插件,三部分

Native和H5之间提供统一的桥接模块

Native和插件之间提供统一的桥架模块

如果加⼊ReactNative,那么也要提供Native和ReactNative之间的桥接模块。这个可以先预留, 也可以后再添加。

Step2:横向划分

Native部分进行横划分,因为这一块是最耗资源的部分

最上层是界面层(名字可以叫表现层或者UI层),这⾥里可以借用MVVM的思想。M不不用考虑,由 下层以服务的形式提供。VM仅仅做显示逻辑,在Swift中⽤用struct。这一层是跟产品的交流层,尽量薄,并且能够快速应对变化。业务逻辑等能分出去的功能,一律分出去。核心和重点就是让 Controller只做调度者,万不得已可以酌情参与很少一部分的view工作。

最底层是微服务层(micro service)。这一层提供基本的功能,⽐如网络,缓存,加解密,系统信息,日志,统计等等。微服务的概念是只能供其他模块调用,不能调用其他模块的服务。本层中的模块之间也不能相互调用。这里是一些基础的组件,按照功能划分,相互间的隔离是第一考虑要素。要求高内聚。

中间是服务层(service),这⾥的服务可以调⽤用微服务,也可以相互之间调用。

分三层相对简单一点。当然也可以分出一些接口层,服务层还可以分出公共服务层,业务逻辑层 等。这个可以根据需要灵活配置。但是总体上分三层(界面、服务、微服务)。

不要跨层调用,界面层只能调用服务层提供的服务。服务层可以⾃己完成工作,也可以调用其他 服务或者微服务完成工作。

Step3:层内划分

界面层:按照⻚面进行组织,提供公共的UI组件,可以理解为(M)VM。VM作为将“界面显示” 转换为“数据操作”的媒介,利用Swift的属性观察者特性,进行⼀级绑定。不引入RxSwift等函数式编程的大型第三方库。

服务层:分为公共服务,跳转逻辑,业务逻辑等模块,按照逻辑功能划分。跟具体⻚面不必相关, 跟界面层的接口为各ViewModel种定义的协议。

微服务层:按照功能划分,不设计业务逻辑,分网络、数据库、加解密,日志,统计等功能 框架图

语言选择Swift,最低支持版本iOS8,有条件的从iOS9开始

服务和微服务都以framework的形式提供,模块间的隔离需要重点考虑。

服务service和微服务仅仅是逻辑上的层次结构,在具体的工程组织上,都采用一级framework封 装,相互间的层级和调用采用相互间的依赖隐含表示。

提供一个界⾯面隔离的service.framework,界⾯层只调用它完成所有任务。作用相当于 Foundation。

以workspace的⽅式组织⼯程,第三方管理⼯具采用Carthage。有条件的情况下,微服务以及部 分服务可以采用私有Carthage的形式,更方便复用。

插件也要求以framework的形式提供,不接受.a的静态库。

如果暂时需要用到Object-C、C、C++,都统一成framework的形式,以后逐步用Swift替换。 类图

界面层 AppDelegate、ViewController仅作为调度者存在,不做任何具体的事情。

ViewModel仅仅做显示逻辑相关的事情,仅仅起到将界⾯面转换为数据的作用。用结构体struct,每 个成员都是普通变量,并且都有默认值,代表了页面的确定性。ViewModel是⼀种数据结构,做显 示逻辑的事情。

UI组件仅由View和ViewModel组成,只能包含显示逻辑,不能包含跳转逻辑,业务逻辑等。

ViewModel放UI层和Service层都有一定道理:放UI层表示显示逻辑;放service层表示UI和service 之间的数据接口。考虑再三,觉得还是应该放UI层。ViewModel最大的作⽤还是在于将UI变化转变为数据操作,本质上离UI应该更近一些。

⾄于UI层和Service层之间的接口,还是定义相关的的ViewModel protocol⽐较好。这些protocol的 定义放在service中(由于framework的影响),将ViewModel的一些基本需求放在protocol中。 service中⽤用Model或者还是用其他来满足这个protocol,就不做要求了。用protocol作为接口比单纯用Model做接口要好。因为Model随着后台API定义而变,而protocol只相当于一个基类,类型更灵活

除了定义一个ViewModel的protocol之外,再定义一个是service的protocol,(既然引⼊入service概 念,就可以淡化logic和data的概念)。

界面层保持最轻量级。⻚面跳转逻辑,具体业务逻辑等⼯作全部下沉到服务层来做。

ViewModel是一个struct,主要做显示逻辑,概念相对⽐较小,⼀般⼀个页面⼀个或者多个。而service是一个类,概念比较大,可以多个⻚面共用一个。尺度可以根据具体情况灵活掌握。不同的页面,通过扩展遵循不同的协议区分开来。类本身可能比较大,但是每一部分都是相对比较小的。

服务层

service.framework作为一个粘合层存在,AppDelegate、ViewController只要import service就可以 调⽤相关服务了。

金融.framework、保险.framework等属于业务特有的逻辑 Router、⽤用户、分享等属于业务无关的公共逻辑
层内的各模块间可以相互调用 具体存在形式,单例例、类、或者framework等,可根据具体情况灵活决定。 为了结构清晰,图中的调用关系线只画出了很少的一部分,⼤大部分线都没有画出来。

微服务层 从开发的⻆角度,按照功能分类;是工程师之间交流的技术语言,⽽不是跟产品交流的业务语言 功能⾼内聚,作为被调用的基础模块
模块之间不要存在相互调用的关系
以framework的形式存在。⾼内聚,⾼复用。

iOS - 架构的认识过程,悬崖勒马。的更多相关文章

  1. 对于iOS架构的认识过程

    MVC 经典就是经典,没有之一.iOS中MVC架构,看懂斯坦福大学白胡子老头这张图基本上就可以了.   斯坦福大学MVC架构.png 简单理解,就是Controller对象拥有View和Model对象 ...

  2. iOS 架构模式--解密 MVC,MVP,MVVM以及VIPER架构

    本文由CocoaChina译者lynulzy(社区ID)翻译 作者:Bohdan Orlov 原文:iOS Architecture Patterns 在 iOS 中使用 MVC 架构感觉很奇怪? 迁 ...

  3. 李洪强iOS开发之基于彻底解耦合的实验性iOS架构

    基于彻底解耦合的实验性iOS架构   这周我决定做一个关于彻底解耦合的应用架构的实验.我想探究的主题是: “如果所有的应用内通讯都通过一个事件流来完成会怎么样?” 我构造了一个待办事项应用,因为这是我 ...

  4. FFmpeg for ios架构:中级

    FFmpeg这部分想了非常久,也没找到比較好的解说方式.本来想像其他博客一样.对着代码一行行的分析.但后来感觉不太现实,FFmpeg应用在IOS上怎么说代码最少也有个5.6k行(包含音视频.业务逻辑) ...

  5. iOS App的启动过程

    一.mach-O Executable 可执行文件 Dylib 动态库 Bundle 无法被连接的动态库,只能通过 dlopen() 加载 Image 指的是 Executable,Dylib 或者 ...

  6. iOS 架构模式-MVVM

    iOS 架构模式-MVVM MVVM Model-View-ViewModelMVVM 其实是MVC的进化版,他将业务逻辑从VC中解耦到ViewModel,实现VC的瘦身. 做一个简单的登录判断: 创 ...

  7. iOS程序启动的过程及原理

    iOS程序启动的过程及原理 文字部分 先执行main函数,main内部会调用UIApplicationMain函数 UIApplicationMain函数里面做了什么事情??? 1> 创建UIA ...

  8. Info.plist和pch文件的作用,UIApplication,iOS程序的启动过程,AppDelegate 方法解释,UIWindow,生命周期方法

    Info.plist常见的设置 建立一个工程后,会在Supporting files文件夹下看到一个“工程名-Info.plist”的文件,该文件对工程做一些运行期的配置,非常重要,不能删除 注:在旧 ...

  9. IOS架构师之路:我对IOS架构的点点认识(大纲)

    1.今天我鼓起了勇气,想纪录自己对IOS架构学习成长的点点滴滴. 从事IOS开发也有几年的时间,从刚開始最主要的语言.界面.逻辑,再到后面复杂点的线程.数据处理.网络请求.动画,最后到最复杂的底层音视 ...

随机推荐

  1. Winform----自定义控件之半透明遮罩(蒙版遮盖指定控件)

    先贴运行效果图,源码点击这里下载 1.新建自定义控件 2.实现功能   namespace UserControlLib   {   [ToolboxBitmap(typeof(ZhLoading)) ...

  2. 07-C#笔记-运算符

    1. 支持++和-- 含义和C++中相同 2. 条件运算 同C++ 3. 位运算 ^ 异或 ~ 取反 4. 支持?:运算 5. 特殊 is 判断对象是否为某一类型. If( Ford is Car) ...

  3. janusgraph的数据模型

    janusgraph的数据模型--->参考 1.简介 janusgraph的数据模型,就是一数据结构中得图结构相似.所以janusgraph的数据schema主要定义在三个要素上:顶点,边,属性 ...

  4. git blame (10)

    git blame system_server.c 每一行提交的sha ,作者,提交的日期及提交的信息

  5. ESA2GJK1DH1K升级篇: 远程升级准备工作: 安装Web服务器

    前言 大家可以安装Apache,Tomcat,nginx 等Web服务器软件,这篇文章安装 OpenResty 作为Web服务器软件,该软件安装在云端电脑,如果想 安装到自己本地电脑实现该功能,可使用 ...

  6. 【border树】【P2375】动物园

    Description 给定一个字符串 \(S\),对每个前缀求长度不超过该前缀一半的公共前后缀个数. 共有 \(T\) 组数据,每组数据的输出是 \(O(1)\) 的. Limitations \( ...

  7. sparksql基础知识二

    目标 掌握sparksql操作jdbc数据源 掌握sparksql保存数据操作 掌握sparksql整合hive 要点 1. jdbc数据源 spark sql可以通过 JDBC 从关系型数据库中读取 ...

  8. 解决github clone慢的问题

    github clone非常慢,解决方法,首先要有vpn 参考 https://www.zhihu.com/question/27159393 第一种方法 这种是没有vpn的方法,测试从10k到 几十 ...

  9. 2019-2020-1 20181218《Linux内核原理与分析》第一周作业

    目录 问题和参考 有趣/有用的Linux命令 小作业和解答 一些图片 相关学习 本文是学习Linux基础入门(新版)后的总结. 问题和参考 虚拟机莫名崩溃,一天重启了几十次电脑,重装两次系统,心累.想 ...

  10. nginx出现403 Forbidden错误

    问题描述:将webpack打包的react前端部署到nginx上,发现出现403 Forbidden错误 解决方案:修改nginx.conf文件,添加user root;配置