iOS基础 - 架构模式:MVP

▶ 什么是 MVP

MVP 是 MVC 设计模式派生出来的,它经常用来创建用户界面

 

MVP 工作原理

A. MVP 中 Presenter 完全把 Model 和 View 进行了分离,主要的程序逻辑在 Presenter 里实现。模型与视图完全分离,我们可以修改视图而不影响模型

B. Presenter 与 View 是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更 View 时可以保持 Presenter 的不变。实际开发中往往可以将一个 Presenter 用于多个 View,而不需要改变 Presenter 的逻辑。这个特性非常的有用,因为 View 的变化总是比 Model 的变化频繁

C. 所有的交互都发生在 Presenter 内部,可以更高效地使用 Model 

注:程序逻辑主要在 Presenter 里实现,其中的 Model 是很薄的一层;View 也是很简单的,能够把信息显示清楚就可以

MVP 与 MVC 有着一个重大的区别:MVP 中 V 并不直接使用 Model,它们之间的通信是通过 Presenter 来进行的,所有的交互都发生在 Presenter 内部!就算是 Model 和 View 之间存在数据交互,也仅仅提供最简单的 setter/getter

MVP 的缺点/优点

A. 好处

可以编写测试用的 View 模拟用户的各种操作,从而实现对 Presenter 的测试,而再不需要使用自动化的测试工具

可以在 Model 和 View 都没有完成时候就可以通过编写 Mock Object(实现了 Model 和 View 的接口,但没有具体内容)来测试 Presenter 的逻辑

注:就是说完全可以脱离用户接口来实现单元测试

B. 坏处

由于对视图的渲染放在了 Presenter 中,所以视图和 Presenter 的交互会过于频繁

Model 亦是如此,MVP 模式容易造成接口类爆炸、类文件和接口文件过多的问题,从而增大包的体积

▶ MVP 实战

MVP 在 iOS 中的表现无非就是让 P层 承担了 Controller 的功能,M、V 两层依旧保持不变。实现方法也很简单,我们只需利用属性把 P层 和 C层 绑定在一起即可(互为彼此时注意循环依赖问题)

具体实现:首先将 P层 和 C层绑定;其次 P层 完全充当了 C层 的功能:比如创建视图、数据交互....

// - UIViewController.m

复制代码
#import "ViewController.h"
#import "TestPresenter.h"
@interface ViewController()
// 绑定 Presenter
@property(nonatomic,strong)TestPresenter *presenter;
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor cyanColor];

    // Presenter
    self.presenter = [TestPresenter new];
    self.presenter.controller = self;
    // 入口方法:在 P 中处理原 C 负责的事
    [self.presenter setUP];
}
@end
复制代码

// - TestPresenter.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface TestPresenter : NSObject
// 绑定 Controller:就是为了让 P 拿到 C 来承担 C 的功能
@property(nonatomic,weak)UIViewController *controller;
// 方法接口
-(void)setUP;
@end

// - TestPresenter.m:所有的事情全部在 P层 处理

复制代码
 1 #import "TestPresenter.h"
 2 #import "TestView.h"
 3 #import "TestModel.h"
 4 @interface TestPresenter()<TestViewDelegate> // 接受协议
 5 
 6 @end
 7 
 8 @implementation TestPresenter
 9 
10 // P 完全负责 V、M 的交互
11 -(void)setUP{
12     NSLog(@"---- P、C 两者绑定成功 -----");
13     [self makeSomethings];
14 }
15 
16 -(void)makeSomethings{
17     
18     // 加载视图
19     TestView *tView = [[TestView alloc] initWithFrame:CGRectMake(30, 80, self.controller.view.frame.size.width - 60, 200)];
20     tView.backgroundColor = [UIColor redColor];
21     [self.controller.view addSubview:tView];
22     tView.delegate = self;
23 
24     // 加载数据模型
25     TestModel *tModel = [TestModel new];
26     tModel.name = @"QQ";
27 
28     // 赋值
29     tView.TVLabel.text = tModel.name;
30     // V 可向 M 提供一些简单入口进行交互
31     [tView setName:tModel.name withimage:nil];
32 }
33 
34 // 代理:随机色
35 - (void)doSomethings{
36     self.controller.view.backgroundColor = [UIColor colorWithRed:arc4random()%255/255.0
37                                                            green:arc4random()%255/255.0
38                                                            blue:arc4random()%255/255.0
39                                                            alpha:1.0];
40 }
41 
42 @end
复制代码

// - TestView.h

复制代码
#import <UIKit/UIKit.h>
@protocol TestViewDelegate <NSObject>
// 协议原本是用来为 C层 制定的,现在 P层 充当了 C层的功能
// 所以我们要在 P层 中接受该协议
-(void)doSomethings;
@end

@interface TestView : UIView
@property(nonatomic,strong)UILabel *TVLabel;
@property(nonatomic,weak)id<TestViewDelegate>delegate; // 代理
// V层 可为 M层 提供一些简单入口
-(void)setName:(NSString *)name withimage:(UIImage *)image;
@end
复制代码

// - TestView.m

复制代码
#import "TestView.h"
@implementation TestView

- (instancetype)initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if (self) {

        self.TVLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 40, self.frame.size.width -40, self.frame.size.height -80)];
        self.TVLabel.backgroundColor = [UIColor orangeColor];
        self.TVLabel.textAlignment = NSTextAlignmentCenter;
        [self addSubview:self.TVLabel];
    }
    return self;
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    if ([self.delegate respondsToSelector:@selector(doSomethings)]) {
        [self.delegate doSomethings];
    }
}

-(void)setName:(NSString *)name withimage:(UIImage *)image{
   // 可根据 M层 的数据进行 UI布局
}

@end
复制代码

// - TestModel.h

#import <Foundation/Foundation.h>
@interface TestModel : NSObject
@property(nonatomic,copy)NSString *name;// 数据源
@end

运行效果

 

posted on   低头捡石頭  阅读(835)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示