本文根据http://gaoyong.diandian.com/post/2011-11-02/6443926处的文章进行整理删减
一、MVC的概念
MVC是Model-VIew-Controller,就是模型-视图-控制器,这些都是什么东西呢?
1、Model = 你的程序是什么(而不是你的程序是如何显示的)
例如,“打飞机”的游戏,Model就是:你的小飞机的攻击力、武器、血等等。再概括点说,就是你的程序将要实现的功能,或者是它所能干的事情。
2、Controller = 如何使你的模型呈现给用户(程序逻辑)
Controller是程序内部的逻辑,它是Model和View沟通的桥梁,它处理View发来的用户的输入。
例如,你按开炮的键子,Controller就会通过内部的逻辑来处理你的要求,并在屏幕上做出相应的显示,你将看到屏幕上的小飞机发出炮弹击中敌机。这也是Controller控制View的显示的例子。
3、View = 在屏幕上你所看到的(是你的Controller的“木偶”,有Controller来操作它的表现)
接着前面的小飞机,View就是:你的小飞机是什么样子的,有一个还是两个翅膀,有几挺枪炮;还有,你的飞机在屏幕上的位置等等。总之,你在屏幕上看到的组件都可以归类为View。
MVC可以帮助确保帮助实现程序最大程度的可重用性。各MVC元素彼此独立运作,通过分开这些元素,可以构建可维护,可独立更新的程序组建。
二、M V C之间的交流模式
我们来看看下面的图,此图出自斯坦福大学CS193课程的课件。
1、M<->V之间有两条黄线,它意味着你不能穿越这黄线,任何一个方向都不行。
2、在图的上部,你可以看到白色的虚线,它意味着你可以自由的穿越它,只要是安全的。
3、白色的实线代表你可以穿越,但你必须要买票,或者交点过路费。
1、C->M
C和M之间的绿色箭头方向就代表着“发起对话”的方向,发起对话的是C,而做出回答的是M。C可以问M各种各样的问题,但M只是回答C的问题或要求,M不可以主动的向C要求什么。
如果用代码来说明这件事情,就是说,C可以导入M的头文件或是M的接口(API)。C可以通过M的API肆无忌惮的向M要求这要求那。
2、C->V
C可以直接地向V进行交流。你可以想想,C要把V放到屏幕上,设置V的属性,告诉它们什么时候从屏幕上消失等等。如果C不能自由的向V发号施令的话,那么V就无法流程的展示。
可能你已经注意到了,这个箭头上还有outlet(输出口),outlet可以看作是从C指向V的指针,它在C中被定义。outlet使我们在C的内部就可以轻松准确地向V施令。C可以拥有很多的outlet。
3、M<->V
我们是不允许M和V进行交流的。我们不希望这三部分之间有过多的交流,假如V在显示时出现了问题,比如有一个图形没有显示出来,我们就要去查找错误,因为C可以和V交流,M也可以和V交流的话,我们就要去检查两个部分。相反的,只有C可以和V交流的话,在出错时,我们就只需要去C那里查找原因,这样查找错误不就很是简单了么?所以,M<->V之间是两条黄线。
4、V->C
在MVC中,程序与用户的交互通过V来实现,但V只是视图而已,并不能完全处理用户的要求,所以,这就要求V必须有某种手段来向C发送信息,移交用户的交互要求。V向C发送消息有以下三种方式:
(1)目标操作(target-action)
C会在自己的内部“悬挂”一个目标(target),如图中的红白相间的靶子。对应的,它还会给将要和它交流的视图对象分发一个操作(action),如图中的黄色箭头,这个视图对象可能是屏幕上的一个按钮。
当按钮被按时,action就会被发送给与之对应的target,这样V就可以和C交流了。但是在这种情况下,V只是知道发送action给对应的target,它并不知道C中的类,也不知道它到底发送了什么。target-action是我们经常使用的方法。
(2)委托(delegate)
有时候,V需要和C进行同步,用户交互不再仅仅是按按钮,划滑块。
图中的delegate黄色箭头上又分出了四个小箭头:should、did、will、还有一个没标注的。绝大部分的delegate信息都是should、will、did这三种形式。A、should代表视图对象将询问C中的某个对象“我应该这么做么?”。举个例子,有一个web视图,有人点击了一个链接,web视图就要问“我应该打开这个链接么?这样做安全么?”。B、will就是“我将要做这件事了”。C、did就是“我已经做了这件事”。
C把自己设置为V的委托(delegate),要让V知道:如果V想知道更多的关于将如何显示的信息的话,就向C发送delegate信息。通过接受V发过来的delegate信息,C就会做出相应的协调和处理。还有一点,每个V只能有一个delegate。
(3)数据源(datasource)
V不能拥有它所要显示的数据,记住这点非常重要。当V需要数据时,V就会请求别人把需要的数据给它。看图中的datasource箭头和delegate类似,V会发送cout,data at信息给C来请求数据。
5、M->C
M和C之间的白色实线意味着M不可以直接地,没有限制的对C进行交流。但当M中的一些东西发生变化时,C需要了解这些变化,我们怎么才能让C知道M的变化呢?
通知(Notification)和KVO是解决问题的好方法。当M中的某些东西发生变化时,他们会向C发出通知“嘿,老兄,注意了啊,我这发生变化了”,或者他们会发出指向变化的指针给C。
6、总结
cocoa忠实于MVC,所以理解cocoa的MVC是我们关键的开始。
C->M:API
C->V:Outlet
V->C:Target-action, Delegate,Datasource
M->C:Notification,KVO
三、MVC三者交流的总结
1、View不允许直接引用Controller和Model。View很专一地被Controller控制来进行数据的显示和接收用户的交互。我们知道View显示的时候需要数据,我们也知道在View上会产生事件。如果要达到不和Controller,Model直接打交道,就需要机制来支持。
在Objective-C中有Protocol的东西,(1)提出Delegate(代理模式)就是来解决UIView想和Controller松耦合互动问题的。(2)iOS还提供了Action-Target模式来让Controller监听View的事件。(3)那对View如何获得数据,iOS中提了Data Source的概念,其实也是Protocol的应用。