iOS 的 MVC

之前一直在听斯坦福大学的公开课: iOS 7应用开发,讲课的是一个非常犀利的白胡子老头,在一个个实例中讲解 iOS 开发,是绝佳的 iOS 入门课程。

在第一节课中就讲了 iOS 中的 MVC,之前一直不太熟悉,回想起来,白胡子老头的总结还是很精准的。

iOS 中的 MVC

所谓的 MVC 是指:

  • Model: 数据的拥有者,实现具体的业务逻辑。
  • View: 具体的用户界面,如按钮、列表、图片。
  • Controller: 负责将 View 中用户的动作传达给 Model,将 Model 的数据通过 View 展现出来。

通常 iOS 的每个场景(scene)都由一个 ViewController 来管理,这个 ViewController 可以是库中原生的,更多情况下是我们自定义的,但是都继承自 UIViewController。顾名思义,ViewController 包含了 MVC 中的 Controller 和 View,其中的 View 一般是系统提供的 UIButton、UILabel 等类的实例。而 Model 一般都是我们自定义的类。

MVC 之间的交互

白胡子老头的 Keynote

View 与 Controller

View 与 Controller 的关系是十分紧密的,他们之间可以双向通信。

Controller 可以直接操作 View。在使用 Storyboard 进行界面设计时,我们可以直接拖拽现有的控件(View),再通过 Controller—Drag 就可以为各种 控件生成一种类似于句柄的 outlet来作为 ViewController 的属性,ViewController 通过 outlet 来对 View 进行操作,设置其外观、状态或者行为等等。如果是通过纯代码来编写界面,ViewController 类中就包含了控件的实例,直接通过这些实例的指针进行操作即可。

View 可以通过特殊的方式来发消息给 Controller。因为系统自定义的 View 并不知道当用户进行操作之后,Controller 需要做些什么,为了减少耦合性,采用了一些特殊的方式来与 Controller 进行通信。通信的方式有:

  • IBAction。通过 Controller—Drag,XCode 会自动生成事件的响应方法。也可以使用(void)addTarget:(id)target action:(SEL)action方法来注册事件的响应方法。
  • DataSource。当系统的某些 View 在呈现时需要我们提供相应的数据。我们必须为 View 指定 DataSource,并实现相应的 DataSourceProtocol(所谓的 Protocol 是指预先定义好的一组回调函数,其中的部分是必须实现的,部分是可选的。)最典型的是 UITableView,我们必须告诉系统这个 TableView 有多少行,每行的 Cell 内容是什么。
  • Delegate。它也是一组 Protocol,系统会在特定事件(如网页的跳转、网页加载)发生的前后来调用这些方法。View 可以在不知道某个类的细节的情况下,把该类设置成自己的 Delegate,只要目标类实现了 Protocol 中的必须实现的方法。这些 Protocol 中的方法的命名是有规律的,通常会包含三种关键字:
    • will: 表示这个方法会在某种事件发生前调用。
    • did: 表示这个方法会在某种事件发生后调用。
    • should: 通常用来确定该不该让某件事发生。如webView:shouldStartLoadWithRequest:navigationType:,它的返回值是布尔型,当返回 NO 时,WebView 将不会加载内容。

Model 与 Controller

Controller 直接向 Model 请求数据。一般将 Model 的类作为 Controller 的属性,直接调用相应的实例方法或者类方法即可。

Model 通过 Notification 和 KVO 将数据的变化通知给 Controller。KVO 是指 Key-value observing,是一种观察者模式的实现,可以使得 Controller 在 Model 的数据变化时能够得到通知。Notification 是另外一种系统提供的通知机制,与 KVO 的直接通知到观察者对象不同,系统提供了一个 NotificationCenter 来广播通知。两者都可以实现一对一或一对多的关系。

Model 与 View

他们不能相互发送信息。

给鸡排饭加个蛋