概念
MVC.pngMVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
简单的说一下这张图吧,这就像是一张MVC中的“交通规则”图,在其中制定了它们之间的通信规则。
- Model和View永远不能相互通信,只能通过Controller传递。
- Controller可以直接与Model对话,Model通过Notification和KVO机制与Controller间接通信。
- Controller可以直接与View对话,通过outlet,直接操作View,outlet 直接对应到View中的控件,View通过action向Controller报告事件的发生。Controller是View的直接数据源。Controller是View的代理,以同步 View与Controller。
拿一个简单的需求举个例子,向一个UItableView的cell绑定数据。日常开发中,我们应该经常写这样的代码。
创建一个数据model,在里面定义我们需要的属性和构造方法。
#import <Foundation/Foundation.h>
@interface XKModel : NSObject
+ (instancetype)modelWithDict:(NSDictionary *)dict;
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) NSString *detail;
@end
#import "XKModel.h"
@implementation XKModel
+ (instancetype)modelWithDict:(NSDictionary *)dict {
XKModel *model = [[self alloc] init];
[model setValuesForKeysWithDictionary:dict];
return model;
}
@end
接下来自定义cell
#import <UIKit/UIKit.h>
#import "XKModel.h"
@interface XKTableViewCell : UITableViewCell
@property (nonatomic, strong) XKModel *model;
@end
#import "XKTableViewCell.h"
@implementation XKTableViewCell
- (void)awakeFromNib {
[super awakeFromNib];
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) {
}
return self;
}
- (void)setModel:(XKModel *)model {
_model = model;
self.textLabel.text = model.title;
self.detailTextLabel.text = model.detail;
}
@end
在控制器中绑定数据显示在界面上
#import "ViewController.h"
#import "XKModel.h"
#import "XKTableViewCell.h"
static NSString *identifier = @"cellID";
@interface ViewController ()<UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) NSArray *dataSource;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initDataSource];
[self.view addSubview:self.tableView];
}
- (void)initDataSource {
NSDictionary *dict = @{@"title":@"浪漫恋星空",
@"detail":@"MVC"};
XKModel *model = [XKModel modelWithDict:dict];
NSMutableArray *dataArray = @[].mutableCopy;
for (int i = 0; i < 10; i ++) {
[dataArray addObject:model];
}
self.dataSource = dataArray.copy;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.dataSource.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
XKTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[XKTableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
}
cell.model = self.dataSource[indexPath.row];
return cell;
}
- (UITableView *)tableView {
if (!_tableView) {
_tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStylePlain];
_tableView.backgroundColor = [UIColor whiteColor];
_tableView.dataSource = self;
_tableView.delegate = self;
_tableView.tableFooterView = [[UIView alloc] init];
}
return _tableView;
}
@end
做完这些,一个简单的需求就完成了。common + R 一下,完美运行。心里可能就在想了,弱鸡产品,提的需求哥分分钟搞定。而且代码写得异常规范。看看这MVC,看看这代码风格。感觉离出任CEO,迎娶白富美,走向人生巅峰的日子不远了啊。
我相信,或许这就是很多人认为的MVC。很长的一段时间里,我也是这样认为的。而且这样写起来也方便啊。但是停下来,仔细想想。在自定义的cell中,我们是直接定义了一个model的属性,作为View的cell直接耦合了一个数据model,这就意味着View的数据输入已经被确定了一定是XKModel。既然这样的话,View就已经谈不上复用了。因为它的数据输入已经被定死了。假定有这样一个需求场景,里面的cell还是长这样,但是这次我想要显示的是姓名和年龄。或许大多数的人会想到,这有什么难的,再定义一个model,依葫芦画瓢,再在cell中定义一个model属性,重写setter方法,So easy!停!!!有没有发现,从一开始,我们错误的理解了MVC。后来很久我在想一个问题,也许是iOS中一开始就给我们一个误解,什么误解呢,那就是UIViewController这样的类名设计,让我们在潜意识里认为ViewController一定是MVC中的Controller层。也许还有一部分原因是因为像UIButton,UILabel等太多系统定义好的简单的View,它们没有必要需要一个Controller层来配合。总而言之呢,我们貌似是用了一个假的MVC。
大多数情况下,我们的UIViewController更多的是作为一个需求场景,而需求场景需要做的事呢,就是根据需求对各个模块进行配置和负责UI布局,让各个模块去做自己的事就好了。每个模块的展示和交互都由它自己对应的MVC去完成。需求场景只要做一些强相关的业务逻辑即可。
我所理解的差不多就这些。这里有一篇文章,是我目前为止看到的讲MVC的文章中讲得最好的,本文的大部分思想也是来自这篇文章。
既然已经发现以前的理解是有问题的,那么在接下的开发中,要更多的去思考怎样才能写出复用性和可维护性更高的代码。
网友评论