现在的位置: 首页 > 综合 > 正文

利用 Delegate Design Pattern 进行 View Controller 之间的沟通

2014年01月30日 ⁄ 综合 ⁄ 共 2901字 ⁄ 字号 评论关闭

如果你是 Objective-C / Cocoa Touch 的重度使用者,那么你一定被一个东西困扰过:不同的 View Controller 之间,如果互相进行沟通?

举个常见的例子。假设我们手头上有一个 UIViewController 实例,名叫 parentViewController ,在这个 parentViewController 生命周期的某个节点,它需要以 modal view controller 的形式 present 一个 UIViewController 实例。这个将要被 present 的 UIViewController 实例名叫 childViewController。

也就是说,在 parentViewController 的代码中,我们应该会看到以下这句话。

[self presentModalViewController:childViewController animated:YES];

以上的描述和代码都非常的顺其自然。然而我们很快会发现一个问题,当这个 childViewController 需要被 dismiss 时,由哪个 view controller 实例负责 dismiss ?

此时答案不唯一。我们有两种选择,两种都可行,但有区别。

第一种选择,由 childViewController 自己负责,把自己给 dismiss 掉。代码很简单。

[self dismissModalViewControllerAnimated:YES];

第二种选择,由 parentViewController 负责,把 childViewController 给 dismiss 掉。代码要复杂一些,分两步。

  1. childViewController 通知 parentViewController ,请求 dismiss 。
  2. parentViewController 收到通知,执行 dismiss , childViewController 生命周期结束。

“第一种和第二种看似区别不大,而且第一种方法的代码量很小。我们就采用第一种,忘掉第二种吧。”

别。千万别。第一种虽然很多时候不致于给你添 Error ,但是非常危险。你应该忘掉第一种,记住第二种。实际上,第一种做法是钻了 Cocoa Touch 的空子,虽然偶尔能用而且不致于添 Error ,但是非常不规范,应当摒弃。这两种方式的区别,具体来说。

  1. 第一种方式,由 childViewController 自行 dismiss 掉自己,并不通知 parentViewController。这导致 parentViewController 虽然拥有 present 下属 childViewController 的权利,但一旦 present 结束,便完全失去了对 childViewController 控制。下一秒钟, childViewController
    是否仍然存在,它所含有的成员变量是否能够被正常访问, parentViewController 将会一无所知。
  2. 大多数情况下, childViewController 完事后,需要和 parentViewController 进行沟通,在自己生命周期结束之际,将由自己负责采集、计算的信息交给 parentViewController 保管(retain / copy)。很明显,第一种方式完全无法实现这个“托管”的功能。

第二种方式其实有一个很正式的名字, Delegate Design Pattern in Objective-C 。没错,它只是一种 Design Pattern ,是一种编程风格,并不是你在代码里必须要做的事情。但是这种编程风格实在是很实用,以至于被 Xcode 的官方模板 Utility Application 所直接采用。 Delegate Design Pattern 看上去很复杂,实现起来其实不难,格式非常固定。我们看看 Utility Application 是怎么做的。

这是 Utility Application 中 FlipsideViewController 对应的 .h 文件。 FlipsideViewController 对应于我们上面描述里的 childViewController 。

#import <UIKit/UIKit.h>

@protocol FlipsideViewControllerDelegate;

@interface FlipsideViewController : UIViewController {

id <FlipsideViewControllerDelegate> delegate;

}

@property (nonatomic, assign) id <FlipsideViewControllerDelegate> delegate;

- (IBAction)done:(id)sender;

@end

@protocol FlipsideViewControllerDelegate

- (void)flipsideViewControllerDidFinish:(FlipsideViewController *)controller;

@end

从上面的代码里,我们不难发现,在 childViewController 的层面上,实现 Delegate Design Pattern 的方法其实很固定,总结一下,有这么几个要点。

  1. 我们首先需要声明一个协议,如上面代码中的 FlipsideViewControllerDelegate 协议。有了这个协议,我们就能确保,负责 present 我们的 FlipsideViewController 的 parentViewController 一定会实现flipsideViewControllerDidFinish: 这个用来“临终托管” FlipsideViewController 的方法。(否则编译时我们会得到一个
    Warning )
  2. 我们需要有一个 property 属性为 assign 的指针。这个指针由 FlipsideViewController 所有,用来记录自己的 parent 是谁。注意,属性必须为 assign 而不能是 retain 或者 copy 。(否则。。你的内存管理会很难看。。)

剩下的事情就简单了。当我们的 FlipsideViewController 被初次 alloc 和 init 后,将它的 delegate 指向将要 present 它的 parentViewController 。于此同时,我们需要确保 parentViewController 实现 flipsideViewControllerDidFinish: 函数,因为这个函数将是 FlipsideViewController 和 parentViewController “临终通讯”的接口。然后,我们就没事了。下一次
FlipsideViewController 生命周期将要结束时,它的 delegate ,也就是 parentViewController 将会及时收到通知,并负责保存信息和移除 FlipsideViewController 。借助 Delegate 风格的帮助,整个流程都将变得非常干净利索。

转载地址:http://www.diwublog.com/archives/130

抱歉!评论已关闭.