【iOS】MVP模式
文章目录
前言
笔者在之前的iOS开发中学习了MVC架构,最近偶然看到了有关于MVP的内容,下面是笔者对于这部分的内容的一个个人理解。如有纰漏请,还请不吝赐教。
起源
首先我们先来回忆一下我们之前学习的MVC模式:
我们之前学习的经典的MVC模式有很多的优点:
- 代码清晰,职责分明,易于维护。
- 代码复用性高,模型和视图可以在多个控制器中重复使用
但是如果随着业务的增加,代码量和复杂程度都会随之提升,MVC的缺点也就暴露了出来:
- C层很容易就过于臃肿,逻辑代码和业务代码难以分离。
- 视图和模型的交互逻辑难以在多个视图控制器中进行共享和复用
- 难以进行单元测试,以为控制器依赖于视图和模型
MVP 架构模式的诞生正是为了解决这个问题。MVP 架构模式将应用程序分成三个主要部分:模型(Model)、视图(View)和表示器或者叫模型视图协调器(Presenter)。这种架构模式使开发者可以更好地管理代码,提高应用程序的可维护性和可扩展性。
各个层的职能
Model
这里的Model层主要负责处理应用程序的数据,包括数据的获取,存储和处理等。
View
这里我们可以发现View变成了Passive View,这里不难发现这里的Passive其实包括了ViewController这个部分的内容,这里的VIew比原先的View多了一层与用户交互的功能。
Present
这个层级可以说是我们整个MVP架构中最重要的一个组成部分,Present层是Model和View之间的一个桥梁,它让Model和View完全独立开来,在MVC中C层的业务代码很大一部分由MVP层中的P层来完成,让我们的ViewController能够更加专注的完成展示UI,处理用户的一个交互。
业务代码
1. 数据处理:我们就以一个简单的登陆注册界面为例子,我们之前写过的知乎日报的为例。知乎日报首页的内容是不是包括了一个从Model层获取我们的一个最新新闻数据的内容,然后我们需要按照时间顺序让其在View层展示,这里原先的内容是在Model层去实现的,而现在转化的了我们的Present层
2.业务流程:根据用户的交互或者其他条件,触发一个不同的业务逻辑,就好比我们知乎日报首页的一个下滑刷新一样,这个内容也应该在我们的一个VC层中去实现的,但是这里我们将他转交到了我们的一个Present层中去实现。
3. 错误处理:处理业务逻辑中出现的一个异常,例如网络连接失败,数据格式错误之类的。
这里面说到的内容我们在MVP中都是通过Present层去实现的。
MVP的一些规范
这里提供一种目前比较多人使用的规范:
View
层是由UIViewController
和UIView
共同组成;View
层将委托Presenter
层对它自己的操作;Presenter
层拥有对View
层交互的逻辑;Presenter
层跟Model
层通信,并将数据转化成对适应UI的数据并更新View
;Presenter
不需要依赖UIKit
;View
层是单一,因为它是被动接受命令,没有主动能力。
一个简单例子
Model层
model层的内容,同MVC大致相似,也是获取一些简单数据的内容。
objc
NS_ASSUME_NONNULL_BEGIN
@interface MainPageModel : NSObject
@property (nonatomic, copy) NSString* textString;
@property (nonatomic, copy) NSString* imageString;
@end
NS_ASSUME_NONNULL_END
Present层
这个层是负责实现UIViewController和Model层的一个通信的内容。
objc
@interface MainPagePresent : NSObject <PresentProtocol>
@property (nonatomic, weak) id<ViewProtocol> delegate; //这里其实持有的是一个View层的内容
@property (nonatomic, copy) NSArray<MainPageModel*> *model; // 这里其实可以持有一个Service层的引用,通过Service层来获取我们的一个数据层,这里可能会和其他人的代码有些出入
-(void)fetchModel;
- (MainPageData *)dataForIndex:(NSInteger)index; //给主函数的View层传输所有需要的一个内容。实现与Model层的一个通信
@end
Present层对应的协议:
objc
@protocol PresentProtocol <NSObject>
-(void)fetchModel;//定义获取数据的内容,这部分内容还可以提取出一个Service层,然后让Service层来实现对应的获取Model层的一个内容
@end
这里我们来简单看一下实现部分:
objc
- (void)fetchModel {
self.model = @[[[MainPageModel alloc] initWithImageString:@"3.jpg" andText:@"照片1"], [[MainPageModel alloc] initWithImageString:@"4.jpg" andText:@"照片2"], [[MainPageModel alloc] initWithImageString:@"5.jpg" andText:@"照片3"]];
if (self.delegate && [self.delegate respondsToSelector:@selector(reloadCollectionView)]) {
[self.delegate reloadCollectionView]; //获取数据后开始加载数据内容
}
}
View层
这个层主要负责一个布局和处理简单逻辑的功能:
objc
@interface MainPageView : UIView
@property (nonatomic, strong) UICollectionView* collectionView;
@end
@interface MainPageViewController : UIViewController<UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, ViewProtocol>
@property (nonatomic, strong) MainPageView* iView;
@property (nonatomic, strong) MainPagePresent* present;
@end
这里还有一个View层的协议,设置对应View从Present层获得数据的内容,以及和Present可以调用View的一些公共接口
objc
@protocol ViewProtocol <NSObject>
-(void)reloadCollectionView;
@end
有关于UICollectionView的一个设置部分
objc
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 11;
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
MainPageCollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier: @"UICollectionViewCell" forIndexPath: indexPath];
MainPageData* data = [self.present dataForIndex:indexPath.item]; //这部分内容是一个获取对应的对应的Model层的数据的内容
cell.imageView.image = [UIImage imageNamed:data.imageName];
cell.textView.text = data.text;
return cell;
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
界面跳转
根据MVP 模式的设计思路,Presenter 应该只关心业务逻辑的实现,不直接操作View 和进行界面跳转等视图层操作。因此,当需要进行界面跳转时,Presenter 应该将跳转的请求传递给View,由View 负责进行具体的跳转操作。
在这个过程中,Presenter 只需要关心跳转请求的结果是否符合业务逻辑即可。
而跳转后的界面对应的Presenter 可以在界面初始化时由View创建并绑定,与之前的Presenter 进行解绑。所以,界面间通信应该是Presenter 与View 的通信,而不是Presenter 与Presenter 的通信。
优缺点
MVP 的优点:
- 代码更加模块化,易于维护和扩展。
- 视图和模型之间的交互逻辑通过Presenter 进行协调,逻辑更加清晰。
- Presenter 可以通过接口来实现,使得测试更加容易。
但同时,MVP 模式也有不尽人意的地方:
- Presenter 层会增加代码量,增加了开发时间和成本。
- 对于小型应用程序来说,MVP 模式可能会显得过于繁琐。
- Presenter 和View 之间的接口设计可能会变得复杂,需要额外的注意。
小结
这里我们就可以简单实现一个有关于MVP的一个内容,这里也是笔者自己对于MVP这种模式的一个个人理解,之后还会继续学习有关于MVP和MVVM的内容,这里如果有什么问题还请不吝指出。