iOS中的VIPER一文通😁

今天来介绍一个适合构建大型APP或比较大的模块的架构-VIPER;

为什么用VIPER?

什么是VIPER?

伴随着业务的增加、功能模块的增涨我们会发现,代码的结构越来越不清晰、测试也越来越难,陷入了一个恶性循环;

为了使得代码便于维护、结构更清晰、便于测试,这时候我们就需要一种好的架构方式来组织我们的APP代码,这时候VIPER就应运而生;

VIPER这个概念来自于Clean Architecture,VIPER是View, Interactor, Presenter, Entity,Routing,这几个单词的缩写;在Clean Architecture中将整个APP或者说模块用专门的不同的层次来分隔,这使得各个层之间减轻依赖,每个层次负责单一的功能,也符合功能单一的设计原则,也更加的便于测试;

拆分VIPER

viper1.png

View

  • 就是UIViewController/View
  • 展示Presenter传递过来的数据
  • 收集用户输入、或者事件等交互信息回调给Presenter

View是被动的,它等待Presenter传递内容用于展示,它从不主动去向Presenter请求数据;

Presenter

  • 负责协调Interactor和View之间的逻辑
  • 将Interactor传递过来的Model转转换为ViewModel
  • 传递ViewModel给View
  • 处理从View中传递过来的交互事件
  • 在需要的时候,通过调用Router导航到新页面

Presenter是整个VIPER架构的核心,在Presenter中包含驱动UI的来逻辑,他知道什么时候展示什么界面;它负责收集从View中传递过来的数据或者事件,从而去驱动Interactor请求数据、或更新UI;当接收到Interactor传递过来的数据,在将数据转换成ViewModel后,将数据传递给View;

Interactor

  • 包含业务逻辑、规则满足具体的业务需求
  • 负责将Entity转换为Model
  • 知道在数据传递给Presenter前需要执行哪些动作,比如存储、删除数据等
  • 不关心具体的数据来源,通过其他的Server API来获得数据

Interactor包含Entity关联到具体业务的逻辑,比如只有符合某种条件的Entity才会被传递到Presenter,在其内部不应该和任何的UI产生依赖关系;因为Interactor负责的是纯业务逻辑,所以他应该很容易进行测试或者通过TDD进行开发;

Entity
  • 业务数据模型
  • 一般直接是没做过转换处理的接口返回数据
  • 直接也仅和Interactor产生关联
Router
  • 整个模块的入口及出口
  • 一定包含一个方法负责创建当前模块,一般是返回一个关联整个模块的UIViewController;
  • 负责页面的导航,从当前模块到其他模块,比如push、present到新的页面

在VIPER中,页面的切换响应是由Presenter和Router一起承担的,由于Presenter负责收集用户的输入,所以他知道什么时候需要切换到哪个新的页面,而Router内包含有具体的切换方法,知道怎样去切换;

我们也可以将Router中创建整个模块的功能分离出来,创建一个单独的Buider模块,这就是VIPER-B;

更加详细的划分关于VIPER-B,见下图(图片的来源再这里):

viper3.png
其他模块介绍
Buider
  • 整个模块的入口
  • 包含一个创建方法负责创建当前模块,一般是返回一个关联整个模块的UIViewController;
Data Manager
  • 是对负责网络请求的Server,本地存储Server的封装
  • 不负责具体的网络请求或者存储
  • 可以被多个Interactor订阅
Model
  • 是对entity的封装
  • 不是能够直接展示的数据,记得ViewModel的转换时Presenter的工作
ViewModel
  • 由Presenter负责生成
  • 包含有UI需要显示的内容

viper中各个模块的整合

我们知道了各个层次的职责,将所有的层次组合到一起才是一个完整的架构;怎样将这些不同的层整合到一起也是一个问题,根据简单复杂有两个办法;

方法1:
viper2.png
  • 像上图一样,view直接持有present,同时view成为present的代理,这样能够使得他们之间实现双向交互
  • router直接被present持有
  • interactor直接被presenter持有,interactor回调或者通知presenter数据进行更新
方法二:

同样通过协议代替上面的持有,将上面办法中的持有完全由代理代替,即Presentor、View各自成为各自协议的代理;但是需要注意避免循环引用及完全弱引用,其中一方的代理需要用强引用,一方代理需要弱引用;

相关资料

viper-demo-ios

13-architecture/viper/

ios-architecture-patterns

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。