iOS学习笔记——MVC

今天看了一集斯坦福的iOS7开发公开课。里面提到了MVC策略,曾经我也看过一些MVC的文章,但是始终理解不深,今天看完后却有一种恍然大悟的感觉,可能和接触的程序多了也有关系吧。但是那个白胡子大叔讲得确实很清晰明白,配合动画,就让我比较容易理解,事实证明我还是喜欢看动画的。

请注意,下面所说的是公开课的内容和自己基于公开课内容的理解,所以更大程度偏重于iOS下的MVC。

 

什么是MVC

首先要说清楚的是——MVC并不是架构、模式这种高大上的东西,它是一种策略,或者结构。为什么要先把这个说清楚,是因为以前我一直以为MVC是一种模式,会觉得有“一个符合MVC模式的程序”这样的说法,但事实上MVC就只是一个结构而已,这种结构可以在一个程序里面出现多次,甚至可以嵌套,就像金刚石是由一个个的4颗碳原子构成的金字塔重复叠加组成的。

MVC由三部分组成:Model (模型) Controller (控制器)View (视图)

MVC的核心任务是:将合适的内容合适地显示在屏幕上
上面两句话是对MVC的基本概括。进一步,MVC的任务可以分成三个部分,这个三个部分就分别由MVC的三个组成部分来实现:

mvc1

如上图所示,Model包含了程序所需的内容,同时负责程序的业务逻辑,它解释了“程序是什么,是干什么的?”这个问题;View负责程序的显示,更通用的说是“展现”,它完成的是最后一公里,让程序的使用者能看到程序的内容,并与程序交互;Controller完成对内容的抓取(从Model),并将其显示在View上,或者接收View的请求消息,如果是对数据的操作请求,就再将这个消息发送给Model对数据作实际处理。开发者对UI的控制,通过Controller完成,这也是上面两个“合适”的含义。

通过上面的描述,可以总结出几个事实:

  • Model是与UI完全独立的部分,同时Model是程序“存在的理由和运行的基础”。
  • View是通用的展示组件集合,也就是UI框架,针对单个程序而言,它可能只是系统UI框架的子集。View不保存数据,也不操作数据,同时View不具备除交互以外的复杂逻辑。(这里说的数据指业务数据)
  • Controller分别和Model和View通信,UI逻辑是Controller的主要内容,从抽象的角度来说,Controller的工作就是MVC的工作。
    上面的事实分别对Model、View、Controller做出了解释,希望看到这里大家已经有了新的认识和理解。下面解释MVC的通信,当然,这也可以算是我看公开课的笔记。

 

MVC的通信

通信可以理解为消息传递,首先放上所有通信方式的说明:

all

然后具体说明每个部分之间的通信:

1. ControllerModelView的通信是直接通信,是不受限的单向通信。Controller可以任意从Model中取得数据,并控制View的展示方式。

c_to_mv

2. ViewController的通信:

V -> C的通信一共有三种,可以概括为是使用Protocol(协议)实现的代理模式,只是在逻辑和表现上略有区别。在Android开发中,这种方式也非常常见——以onXxx开头的回调方法。我认为公开课讲得更多的是从逻辑上对三种方式的理解,而在实现上应该差距不大,下面分别说明:

第一种可以称为Action通信,它的基础是在通信之前,由Controller设定一个Target,并将Target告知View,当View中需要Controller做出响应时,通过向设定好的Target发出一个Action,Controller在接收到Action时做出响应的响应。场景如响应按钮的点击事件等。

这个Target,在iOS中也称为outlet,感觉像是Controller伸向View的一个触角,大家自行脑补~~

action

第二种称作Synchronize通信,简单的说这种通信是由于View没有足够的逻辑来对交互做出后续响应的操作(注意区别,这里是后续,当然本质上可以理解为一样的,上面已经做了说明)。典型场景如:当用户滚动一个列表之前、滚动中、滚动后,业务上需要做出响应的处理,比如拦截、比如同步滚动等等。这些逻辑是根据显示的内容判断的,而显示的内容是和显示方式无关的,所以超出了View的控制和逻辑范围,需要将消息发送给Controller进行处理。这里也体现了Controller控制显示逻辑这一个事实。

sync

第三种是DataSource通信。这个比较容易理解,View要显示内容,那么就需要在不同的交互过程中加载不同的数据,但上面已经说到,数据是独立于View的,那么就需要Controller提供。当View需要Controller提供数据的时候,View就通过这个通信方式向Controller索要数据。图上的DataSource有一个*号,这里要注意的是,虽然View是向Controller索要数据,但实际上Controller只是逻辑的集合,并不占有数据,当Controller收到数据请求时,还是需要向Model索要数据。这样做的目的:一是使View和Model解耦,降低系统复杂度;二是将数据在交由View显示之前,可以对数据进行重新组织,使之符合当前“界面”对显示的要求。

datasource

3. 最后是ModelController的通信。为什么要有这个通信需求呢?当数据发生变化的时候,可能需要Controller对View的显示方式进行更新,或者进行提示等等,这些操作属于UI逻辑的范畴,不属于业务逻辑。打个比方,保存联系人的时候,联系人信息属于Model,保存的逻辑,比如检查电话号码是否正确、检查是否有重复等等也属于Model,但是储存完成之后是否需要提示?怎么提示?是否需要跳转?等等这些是属于UI逻辑,也就是Controller的内容。所以当储存完成时Model需要告知Controller进行相关处理。

Model像Controller的通信类似于Android里面的Broadcast,也就是广播,在iOS中,这个机制称为Notification或KVO——Key Value Observer,应该也是使用观察者模式实现的吧。这个比较好理解,就不做过多解释了。

radio

总结

说完了MVC的通信模式,在回过头来反刍一下开始的时候提到的MVC的核心任务:将合适的数据合适地显示在屏幕上,会不会有新的理解呢?我也是在了解了通信方式之后才总结出的上面的核心任务,希望能给大家带来帮助。

MVC不管是在App还是在Web应用中都有广泛的应用,是一种实践丰富的设计策略。上面的和课程中有出入的描述,是我看完之后对MVC的一点点理解,希望大家有不同的看法在下面留言或者邮件给我提意见。