iOS DeveloperAndroid 开发模式和优秀框架那些事iOS 开发每天分享优质文章

浅谈MVC&变异MVC&MVP&MVVM

2019-06-19  本文已影响544人  iOS猿_员

稍微做过几年开发的一定都听过MVC、MVP、MVVM这些架构名称吧。其实不论我们用哪一种机构模式,总会有一个地方造成臃肿,我们需要根据我们的具体业务使用更加合适的架构模式。而不能迷信哪种架构模式比较先进什么的。。。

MVC

MVC的优点和缺点都是很明显

对于 MVC,iOS 中最为典型的就是 UITableview 的时候,UITableview 几乎是对 MVC 架构用到了极致。我们平时创建 UITableview、UITableviewCell、Model,这就是最为常见的MVC架构。

今天我们对一个view进行一些实现

APPView代码

@class APPView;
@protocol MyAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(APPView *)appView;
@end

@interface APPView : UIView

@property (nonatomic,strong) UIImageView *iconView;
@property (nonatomic,strong) UILabel *nameLabel;

@property (weak, nonatomic) id<MyAppViewDelegate> delegate;

@end

实现

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
UIImageView *iconView = [[UIImageView alloc] init];
iconView.frame = CGRectMake(0, 0, 100, 100);
[self addSubview:iconView];
_iconView = iconView;

UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.frame = CGRectMake(0, 100, 100, 30);
nameLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:nameLabel];
_nameLabel = nameLabel;
}
return self;
}


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

APPModel代码

@interface APPModel : NSObject

@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *image;

@end

Controller实现

- (void)viewDidLoad {
[super viewDidLoad];


//创建view
APPView *app = [[APPView alloc]initWithFrame:CGRectMake(100, 100, 100, 150)];
app.delegate = self;
[self.view addSubview:app];

//创建model
APPModel *model = [[APPModel alloc]init];
model.name = @"我是一片云";
model.image = @"cloud";

//赋值
app.nameLabel.text = model.name;
app.iconView.image = [UIImage imageNamed:model.image];

}

#pragma mark -- view点击事件 --
- (void)appViewDidClick:(APPView *)appView{
NSLog(@"点击了view");
}

为了更加明白的看出来 MVC,我这里有单独的实现了一个 APPModel,我们查看代码可以看到,大量的业务逻辑需要再 Controller 里面处理。我们需要处理 View 的创建,赋值,实现点击事件,这些功能就造成了 Controller 的臃肿。但是好处也是有的,因为 View 和 Model 互相不知道对方是谁,我们可以重复利用他们。

变异MVC

变异 MVC 其实就是 View 也持有 Model,将 View 内部的细节封装起来了

APPView代码

#import <UIKit/UIKit.h>
#import "APPModel.h"
NS_ASSUME_NONNULL_BEGIN

@class APPView;
@protocol MyAppViewDelegate <NSObject>
@optional
- (void)appViewDidClick:(APPView *)appView;
@end

@interface APPView : UIView

@property (nonatomic,strong) APPModel *model;
@property (weak, nonatomic) id<MyAppViewDelegate> delegate;

@end


//实现
#import "APPView.h"
@interface APPView ()
@property (nonatomic,strong) UIImageView *iconView;
@property (nonatomic,strong) UILabel *nameLabel;
@end
@implementation APPView

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
UIImageView *iconView = [[UIImageView alloc] init];
iconView.frame = CGRectMake(0, 0, 100, 100);
[self addSubview:iconView];
_iconView = iconView;

UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.frame = CGRectMake(0, 100, 100, 30);
nameLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:nameLabel];
_nameLabel = nameLabel;
}
return self;
}


- (void)setModel:(APPModel *)model{
_model = model;
_iconView.image = [UIImage imageNamed:model.image];
_nameLabel.text = model.name;
}

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

@end

代码变化是 view 持有了 Model ,然后把 view 的实现方法了匿名函数里面了。model 的结构还是不变

Controller实现

- (void)viewDidLoad {
[super viewDidLoad];


//创建view
APPView *app = [[APPView alloc]initWithFrame:CGRectMake(100, 100, 100, 150)];
app.delegate = self;
[self.view addSubview:app];

//创建model
APPModel *model = [[APPModel alloc]init];
model.name = @"我是一片云";
model.image = @"cloud";

//赋值
app.model = model;
}

#pragma mark -- view点击事件 --
- (void)appViewDidClick:(APPView *)appView{
NSLog(@"点击了view");
}

在 controller 里面我们不在 controller 里面对 view 进行实现,需要把 Model 的值传给 view

MVP

MVP是 controller 不在持有 View和Model,而是有一个 Presenter 类持有。

Presenter实现

@interface APPPresenter ()<MyAppViewDelegate>
@property (weak, nonatomic) UIViewController *controller;
@end

@implementation APPPresenter
- (instancetype)initWithController:(UIViewController *)controller{
if (self = [super init]) {
_controller = controller;
//创建view
APPView *app = [[APPView alloc]initWithFrame:CGRectMake(100, 100, 100, 150)];
app.delegate = self;
[controller.view addSubview:app];

//创建model
APPModel *model = [[APPModel alloc]init];
model.name = @"我是一片云";
model.image = @"cloud";

//赋值
app.model = model;
}

return self;
}

#pragma mark -- view点击事件 --
- (void)appViewDidClick:(APPView *)appView{
NSLog(@"点击了view");
}

Controller实现

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

self.presenter = [[APPPresenter alloc]initWithController:self];

}

【注意】:要把APPPresenter设置为全部变量,如果设置为局部变量的话,会在出函数以后presenter对象就会被销毁。

其实MVP就是我们在专门做一个APPPresenter类,把controller里面方法给方法APPPresenter类里面

MVVM

使用MVVM最好的框架是ReactiveCocoa,但是这个框架是重量级的框架,学习成本还是比较大的,如果项目中主要使用的架构就是MVVM,那么用这个框架是非常好的,如果只是局部使用的话我们可以使用KVOController来简单的替代一下

MVVM我感觉好像跟MVP有点类似,但是比MVP多了一个功能,就是在view改变时,model也能及时改变,在model改变时view也能及时改变

APPView代码

#import "APPView.h"
#import "NSObject+FBKVOController.h"
@interface APPView ()
@property (nonatomic,strong) UIImageView *iconView;
@property (nonatomic,strong) UILabel *nameLabel;
@end
@implementation APPView

- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
UIImageView *iconView = [[UIImageView alloc] init];
iconView.frame = CGRectMake(0, 0, 100, 100);
[self addSubview:iconView];
_iconView = iconView;

UILabel *nameLabel = [[UILabel alloc] init];
nameLabel.frame = CGRectMake(0, 100, 100, 30);
nameLabel.textAlignment = NSTextAlignmentCenter;
[self addSubview:nameLabel];
_nameLabel = nameLabel;
}
return self;
}


- (void)setModel:(APPModel *)model{
_model = model;
_iconView.image = [UIImage imageNamed:model.image];
_nameLabel.text = model.name;


__weak typeof(self) waekSelf = self;
[self.KVOController observe:model keyPath:@"name" options:NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
waekSelf.nameLabel.text = change[NSKeyValueChangeNewKey];
}];

[self.KVOController observe:model keyPath:@"image" options:NSKeyValueObservingOptionNew block:^(id  _Nullable observer, id  _Nonnull object, NSDictionary<NSKeyValueChangeKey,id> * _Nonnull change) {
waekSelf.iconView.image = [UIImage imageNamed:change[NSKeyValueChangeNewKey]];
}];

}

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

在实现model的set方法时,要监听model值的变化。

viewModel的实现

- (instancetype)initWithController:(UIViewController *)controller{
if (self = [super init]) {

_controller = controller;
//创建view
APPView *app = [[APPView alloc]initWithFrame:CGRectMake(100, 100, 100, 150)];
app.delegate = self;
[controller.view addSubview:app];

//创建model
APPModel *model = [[APPModel alloc]init];
model.name = @"我是一片云";
model.image = @"cloud";

//赋值
app.model = model;
}

return self;
}

#pragma mark -- view点击事件 --
- (void)appViewDidClick:(APPView *)appView{
NSLog(@"点击了view");

appView.model.name = [NSString stringWithFormat:@"%d",arc4random()%100];

NSLog(@"%@",appView.model.name);
}

viewModel 实现跟 Presenter 实现是类似的。

文章来源网络,如有侵权,请联系小编删除


推荐文集

* BAT—最新iOS面试题总结

上一篇 下一篇

猜你喜欢

热点阅读