Swift中的VIPER设计模式,用于iOS应用程序开发。
设计模式是上帝给软件开发人员的礼物。 这些技术可最大程度地减少代码重复,防止高度耦合并标准化编写代码的通用方式,从而为开发软件时的重复出现情况提供了通用解决方案。 在这个故事中,我们将熟悉用于iOS开发的称为VIPER (视图,交互器,演示者,实体和路由器)的设计模式。
先决条件:在开始学习VIPER之前,请确保您了解建筑设计模式和委托模式。
什么是毒蛇?
毒蛇是一种实现“关注分离”范式的设计模式。 与MVP或MVC一样,它通常采用模块化方法。 一种功能,一种模块。 对于每个模块,VIPER具有五个(有时是四个)不同的类,具有不同的角色。 任何课程都不能超出其唯一目的。 这些课程如下。
查看:具有所有代码的类,用于向用户显示应用程序界面并获取他们的响应。 在收到响应后,View会提醒演示者。
演示者:模块的核心。 它从视图中获取用户响应并相应地工作。 仅用于与所有其他组件进行通信的类。 调用路由器进行线框图,交互器以获取数据(网络调用或本地数据调用),查看以更新UI。
交互器:具有应用程序的业务逻辑。 主要进行API调用以从源中获取数据。 负责进行数据调用,但不一定来自其自身。
路由器:进行电线成帧。 从演示者那里收听要演示的屏幕并执行该屏幕。
实体:包含交互器使用的普通模型类。
下面显示了VIPER的简单示意图
毒蛇的例子
我创建了一个简单的项目来解释毒蛇。 可以在GitHub上找到。 这是一个非常基本的应用程序,它显示了从外部API获取的新闻标题。 (:p没用)。
Viper是委托驱动的体系结构。 因此,不同层之间的大多数通信都是通过委派执行的。 一层通过协议调用另一层。 调用层从协议中调用函数。 侦听层符合该协议并实现该功能。
下面,我将解释如何在我的一个示例项目中实现VIPER。 我建议您在github中打开项目并阅读说明。
通讯协定
我为所有协议创建了一个单独的文件。
遵循命名约定来命名协议。 例如,“ viewToPresenterProtocol”。 因此,这是一个“协议”,将由“演示者”实施以收听“视图”必须说的内容。
- PresenterToViewProtocol:演示者调用,View侦听。 演示者从该协议接收引用以访问View。 视图符合协议。
- ViewToPresenterProtocol:查看呼叫,主持人收听。
- InteractorToPresenterProtocol:Interactor调用,Presenter监听。
- PresentorToInterectorProtocol:演示者调用,Interactor侦听。
- PresenterToRouterProtocol:演示者呼叫,路由器监听。
应用流程
View具有对“ ViewToPresenterProtocol”的引用以访问“ Presenter”并符合“ PresenterToViewProtocol”。 在它的viewDidLoad()中,它调用协议的函数updateView()。
//视图
var presenter:ViewToPresenterProtocol?
覆盖func viewDidLoad(){
super.viewDidLoad()
主持人?.updateView()
}
另一方面,Presenter符合“ ViewToPresenterProtocol”。 因此,它实现了updateView()函数。
//主持人
var interector:PresentorToInterectorProtocol ?;
func updateView(){
interector?.fetchLiveNews()
}
在updateView()内部,演示者告诉交互者获取一些实时新闻数据。
Interactor符合’PresentorToInterectorProtocol’。 因此,它实现了fetchLiveNews()函数。 此功能尝试进行网络调用并获取数据。 它具有来自“ InterectorToPresenterProtocol”的引用以访问“ Presenter”。
//交互器
var presenter:InterectorToPresenterProtocol?
如果网络调用成功获取了数据,它将调用以下函数。
//交互器
self.presenter?.liveNewsFetched(news:(arrayObject?[0])!)
如果不
//交互器
self.presenter?.liveNewsFetchedFailed()
现在,演示者还符合“ InterectorToPresenterProtocol”。 因此,它实现了这些功能。
//主持人
func liveNewsFetched(news:LiveNewsModel){
查看?.showNews(news:news);
}
func liveNewsFetchedFailed(){
查看?.showError()
}
因此,它告诉视图是显示新闻还是显示错误。
现在,View符合’PresenterToViewProtocol’。 因此,它实现了showNews()和showError()。 在这两个函数中,view用获取的数据或错误填充视图。
实体层
上面在“应用程序流程”部分中,没有讨论实体层。 它不直接与应用程序流连接。 但这是交互器不可或缺的一部分。 实体层提供了一个模型,交互器可以使用该模型从获取的数据中创建对象。
路由器
路由器负责应用程序的布线。 在应用程序中更改屏幕是非常基本的事情。 在VIPER中,路由器层负责执行该操作。
前面我们已经讨论过,在VIPER体系结构中,每个功能都具有一个模块,并且一个模块包含这五个层。 演示者呼叫路由器以创建一个新模块。 然后,路由器首先启动所有层类并返回模块。
在我的示例项目中,应用内模块没有更改。 但是,路由会在应用程序首次启动时发生。 因此,在AppDelegate的’didFinishLaunchingWithOptions()’内部,将调用路由器的createModule()函数。 它返回一个模块。 然后,UIWindow类显示该模块的视图。
为什么和何时使用VIPER
VIPER遵循非常干净的架构。 它将每个模块彼此隔离。 因此,更改或修复错误非常容易,因为您只需要更新特定的模块即可。 VIPER还为采用模块化方法创造了一个很好的单元测试环境。 由于每个模块彼此独立,因此可以很好地保持低耦合。 因此,在共同开发人员之间划分工作非常简单。
当应用程序的需求非常符合要求时,应使用VIPER。 处理不断变化的需求可能会造成混乱和混乱的代码。 因此,不应将其用于小型项目,因为MVP或MVC就足够了。 另外,如果项目的所有开发人员都完全理解该模式,则应使用VIPER。
VIPER工具
如果要在项目中使用VIPER,最聪明的方法是使用自动模块结构生成器。 否则,为模块创建文件将是单调的。 网上几乎没有发电机。
- Generamba
- VIPER代码
- 贵宾根
结论
就像任何其他设计模式一样,VIPER也是不言而喻的。 一个人需要动手才能理解整个图片。 我的建议是首先开始使用VIPER创建一个非常基本的应用程序,并在此过程中阅读在线资源。 我的github仓库也可能是一个很好的参考。
快乐编码🙂
神圣的孟加拉国万岁。
孟加拉国是一个隐喻的世界,高低戏曲,伟大的诗歌和音乐。 您与一个稻农交谈,然后找到了一位诗人。 您会认识清道夫,并且会找到一位出色的歌手。
让·休斯顿
参考 :
- https://medium.com/ios-os-x-development/ios-architecture-patterns-ecba4c38de52
- https://medium.com/@ankoma22/the-good-the-bad-and-the-ugly-of-viper-architecture-for-ios-apps-7272001b5347
- https://github.com/MindorksOpenSource/iOS-Viper-Architecture/tree/master/iOS-Viper-Architecture
- https://sourcemaking.com/design_patterns