iOS中MVC之间的通讯


一,  所谓的 MVC 是指:

Model: 数据的拥有者,实现具体的业务逻辑。

View: 具体的用户界面,如按钮、列表、图片。

Controller: 负责将 View 中用户的动作传达给 Model,将 Model 的数据通过 View 展现出来。

通常 iOS 的每个场景(scene)都由一个 ViewController 来管理,这个 ViewController

可以是库中原生的,更多情况下是我们自定义的,但是都继承自 UIViewController。顾名思义,ViewController 包含了

MVC 中的 Controller 和 View,其中的 View 一般是系统提供的 UIButton、UILabel 等类的实例。而

Model 一般都是我们自定义的类。

二 , MVC 之间的通讯

iOS中MVC之间的通讯
iOS中MVC之间的通讯

1️⃣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 将不会加载内容。

2️⃣Model 与 Controller

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

Model 通过 Notification 和 KVO 将数据的变化通知给 Controller。KVO 是指 Key-value

observing,是一种观察者模式的实现,可以使得 Controller 在 Model 的数据变化时能够得到通知。Notification

是另外一种系统提供的通知机制,与 KVO 的直接通知到观察者对象不同,系统提供了一个 NotificationCenter

来广播通知。两者都可以实现一对一或一对多的关系。

3️⃣Model 与 View

他们不能相互发送信息。

三, View Controller 之间的切换

View Controller 之间的切换主要有三种方式:

Storyboard 的 segue。如果使用 Storyboard 来构建 App,那么只需要 Ctrl-Drag 即可实现 View Controller 的切换,比如将一个按钮 Ctrl-Drag 到另一个 View Controller 上。如果一个 segue 链接的是两个 View Controller,那么就需要用代码来完成跳转,这个时候需要为 segue 来指定一个 Identifier,通过调用performSegueWithIdentifier:sender:来完成跳转。

pushViewController:animated:方法。这个方法需要当前的 View Controller 在一个 UINavigationController 内部。UINavigationController 内部维护了一个栈来保存其中的所有 View Controller,将新的 View Controller push 到栈内就可以完成跳转。

presentViewController:animated:completion:方法。不同于上一种方法,这个方法并不是将 View Controller push 到栈内,而是维护一个 presenting 和 presented 关系。例如有两个 View Controller 分别叫 A 和 B,如果 A 调用此方法来显示 B,相当于 A拥有了 B。A 中的presentedViewController属性会指向 B,B 的presentingViewController属性会指向 A,这个关系是由系统自动维护的。

其中的第二种方法和第三种方法是类似的。他们之间的区别更多的是语义上的区别——presentViewController:animated:completion:方法更多的是在强调打断现有的工作流,展现一组新的 View 来完成某个特定的工作,通常需要向用户获取某些信息^1。它常常用来显示一个模态的 View,一个模态的 View 通常有下面三个特点^2

占据整个屏幕,或者 iPad 上的整个 父View 的区域。

包含了完成一个任务所需的文本和控件。

通常有一个完成按钮和一个取消按钮,点击它们来表示任务的完成情况,并且退出当前的 View。

典型的场景:用户登录、添加一项待办事项。

另外一个值得注意的地方是,在写 App 的时候有必要了解在各个状态下,栈中的 View Controller 都有哪些,以避免重复地

push 同一个 View Controller。并且可以利用 UINavigationController 提供的一系列

pop*ViewController 的方法来快速到达指定的 View Controller。

上一篇:mysql 三范式及逆范式


下一篇:ios 快速判断当前网络状态(三种方法)