浅谈iOS中MVC

作者: 浪漫恋星空 | 来源:发表于2017-04-20 11:43 被阅读3046次

    概念

    MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。

    MVC.png

    简单的说一下这张图吧,这就像是一张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的文章中讲得最好的,本文的大部分思想也是来自这篇文章。

    杂谈: MVC/MVP/MVVM

    既然已经发现以前的理解是有问题的,那么在接下的开发中,要更多的去思考怎样才能写出复用性和可维护性更高的代码。

    相关文章

      网友评论

        本文标题:浅谈iOS中MVC

        本文链接:https://www.haomeiwen.com/subject/bubkzttx.html