为啥 UIViewController 是 UIResponder 的子类?
Posted
技术标签:
【中文标题】为啥 UIViewController 是 UIResponder 的子类?【英文标题】:Why UIViewController is a subclass of UIResponder?为什么 UIViewController 是 UIResponder 的子类? 【发布时间】:2011-05-14 21:57:22 【问题描述】:使UIViewController
成为UIResponder
的子类的目的是什么?是否只是为了传递轮换事件?
我在文档中找不到任何明确的信息。
更新
我了解,如果将某些内容设为UIResponder
,则该内容应该包含在响应者链和流程事件中。但我有两个令人痛心的疑虑。
-
据我所知,
UIViewController
在其view
之后被放入响应者链中。为什么我们在响应者链中需要一个视图控制器?它的view
已经存在,为什么不让视图处理其子视图未处理的事件呢?
好的,我同意我们可能需要这个。但我想看看一些现实生活中的例子,当真正需要在视图控制器中处理事件并且是做某事的最佳/最简单/最合适的方式时。
【问题讨论】:
【参考方案1】:我认为您的问题可能只是面向对象思维的失败。
根据文档:
响应者链是一系列链接到的响应者对象 应用事件或操作消息。
在 UIKit 中,视图控制器位于其视图和控制器被推送到的视图之间的响应者链中。因此,它会提供其视图无法处理的任何事件或动作。
最顶层视图控制器的下一个响应者是窗口,窗口的下一个响应者是应用程序,应用程序的下一个响应者是应用程序委托,而应用程序委托是停止降压的地方。
您的问题“仅仅是为了传递轮换事件吗?”应用不正确的测试;这意味着在某些时候,响应者链已经完全设计好了,有人想‘哦,等等,轮换怎么样?最好将视图控制器放入链中。
最初的问题是:如果没有视图处理事件或动作,视图控制器是否可以处理它们是否有帮助?答案显然应该是“是”,因为即使在触摸屏设备上,也会有与视图没有内在关联的事件或动作。
最明显的例子是那些与屏幕以外的物理输入相关的例子。所以设备旋转是其中之一。蓝牙键盘上的按键是另一种情况。遥控器是第三个。加速度计是第四个。
下一个最明显的例子是任何系统生成的事件或动作,它们应该交给最本地的单个参与者,而不是每个人。在 ios 中,这通常会请求更具体的参与者,例如最本地的撤消管理器或输入视图的标识,以便在焦点出现时显示。
一个不太明显的例子是UIMenuController
示例——一个弹出视图,它发布一个用户输入事件,可能需要遍历多个视图控制器才能到达应该对其进行操作的那个。 iOS 5 的子视图控制器极大地增加了这里的可能性;很多时候,你会拥有一个父视图控制器,它的逻辑是做一堆事情,而子视图控制器想要将消息传递给知道如何处理它们的人,而无需对层次结构进行硬编码。
所以,不,视图控制器并没有被添加到响应者链中,只是为了处理旋转事件。之所以添加它们,是因为逻辑上它们根据响应者链的初始定义属于那里。
【讨论】:
【参考方案2】:这听起来像是一个油嘴滑舌的答案,但实际上并非如此。 UIViewController
是 UIResponder
的子类,因此可以响应用户操作(例如触摸、动作等)。
如果视图不响应事件,它会向上传递响应者链,从而为更高级别的对象提供处理它的机会。因此,视图控制器和应用程序类都是UIResponder
的子类
您可以在 Apple 开发者网站上的 Cocoa Application Competencies for iOS: Responder Object 中找到有关响应者链的更多详细信息。
【讨论】:
没关系。但是,当 UIViewController 实际响应动作(例如触摸)时,您能否给出一些具体示例? 好吧,一个完全人为的例子:假设你有许多 UIImageViews,每个都显示一个动物。当用户触摸你想要播放动物发出的声音时。您可以让视图控制器响应事件并播放适当的声音,而不是让每个视图播放声音。这将允许它在开始新的声音之前停止正在播放的声音。 更好的例子:如果你想在两个子视图之间实现拖放。 对于动物案例,我建议采用不同的设计,当动物的所有信息(外观和声音)被封装在一个模型对象中并呈现在一个视图对象中时,控制器对象刚刚通过数据。 (但是animalView
可能有类似shutUpTheAnimalNow
的方法)。至于拖放,请参阅更新的问题。为什么 UIViewController 的 view
不能处理这个?
更多关于动物:可能是一个子视图animalSoundPlayer
会更好:)【参考方案3】:
UIViewController 在响应者链中允许它处理任何事件。除了您想到的(触摸)事件之外,还有更多通过此链的事件。运动事件通过链传递,特定视图无法处理的触摸事件,您还可以使用带有 nil 目标的 [UIApplication sendEvent:...]
强制通过响应链。
您可能注意到的另一件事是 UIApplication 也是 UIResponder 的子类。所有未处理的事件都将在那里结束。
【讨论】:
我想的不是触摸而是旋转——这是唯一的原因吗?至于 UIAppliction——它是应用程序的主要控制对象,所以我对它作为响应者没有任何疑问。请检查更新后的问题。【参考方案4】:在 MVC 概念中,视图中发生的事件的处理应该执行控制器。
有一个功能,可以将 -[UIControl addTarget:action:forControlEvents:] 的“目标”参数设置为“nil”,以防在响应者链中搜索愿意响应该操作的对象。
也就是说,由于搜索选项,UIViewController 是 UIResponder 的子类。
因此,您可以以相同的方式发送自定义控件事件以获得“搜索”选项的好处。
【讨论】:
以上是关于为啥 UIViewController 是 UIResponder 的子类?的主要内容,如果未能解决你的问题,请参考以下文章
为啥UIView中引用了@UIViewController?
为啥 UIPopoverController 不是 UIViewController 的子类?
为啥 xcode 中 uiviewcontroller 的顶部有间隙?
为啥我们将 UIViewController 传递给 UINavigationController 类?
为啥 UIViewController 在 UINavigationBar 下扩展,而 UITableViewController 没有?