首先要明确的是:在IOS中,有响应者链对事件进行响应,所有的响应类都是UIResponder的子类,响应者链是一个由不同对象组成的层次结构,其中的每个对象将依次获得响应事件消息的机会。
响应链的过程:
当事件发生的时候,响应链首先被发送给第一个响应者(往往是事件发生的视图,也就是用户触摸屏幕的地方)。事件将沿着响应者链一直向下传递,知道被接受并作出处理。一般来说,第一响应这是个视图对象或者其子类,当其被触摸后事件就交由它处理,如果他不处理,时间就会被传递给视图控制器对象UIViewController(如果存在),然后是它的俯视图对象(superview),以此类推知道顶层视图。接下来会沿着顶层视图(top view)到窗口(UIwindow 对象) 再到程序的(UIApplication对象),如果整个过程都没有响应这个事件,则该事件被丢弃,一般情况下,在响应链中只要有对象处理事件,事件就会被传递。
典型的响应路线图如:
First Responser --> The Window -->The Applicationn --> App Delegate
正常的响应者链流程经常被委托打断,一个对象可能将响应工作委托给另一个对象来完成(通常是视图控制器viewcontroller)。
关于响应链的常见问题:
1. 如何调用父类的controller中的方法:
[[self superview].nextResponder method]; 或者 [[[self superview] nextResponder ] method];
这两种方法都可以,但是使用的时候最好是进行判断一下:
- <span style="white-space:pre"> </span>id next = [self nextResponder];
- <span style="white-space:pre"> </span>while(![next isKindOfClass:[ViewController class]])//这里跳不出来。。。有人说这里跳不出来,其实是因为它没有当前这个view放入ViewContro<span style="white-space:pre"> </span>ller中,自然也就跳不出来了,会死循环,使用时需要注意。
- <span style="white-space:pre"> </span>{
- <span style="white-space:pre"> </span>next = [next nextResponder];
- <span style="white-space:pre"> </span>}
- <span style="white-space:pre"> </span>if ([next isKindOfClass:[ViewController class]])
- <span style="white-space:pre"> </span>{
- <span style="white-space:pre"> </span>controller = (ViewController *)next;
- <span style="white-space:pre"> </span>}
2.当一个子view需要接收点击事件,其父view也需要接收点击事件,该如何处理:
按照正常情况下,子类接收点击事件以后,事件不会主动传递到下一个响应者,因此父类便不再接收点击事件。如果子类不处理点击事件,则事件会一直传递下去,直到UIApplication。
但是我们可以使得子类处理过响应事件后仍将响应这传递到下一个响应者。但是我们编写代码才能办到。
- 要做的如下:
- 子view的代码如下:
- - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
- // 这里可以做子view自己想做的事,做完后,事件继续上传,就可以让其父类,甚至父viewcontroller获取到这个事件了
- [[selfnextResponder]touchesBegan:toucheswithEvent:event];
- }
- - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
- [[selfnextResponder]touchesEnded:toucheswithEvent:event];
- }
- - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
- [[selfnextResponder] touchesCancelled:toucheswithEvent:event];
- }
- - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
- [[selfnextResponder] touchesMoved:toucheswithEvent:event];
- }
补充一段摘要:
摘取一部分说明:
“当用户 与 iPhone的触摸屏 产生 互动时,硬件 就会探测到 物理接触 并且 通知 操作系统。接着 操作系统 就会创建 相应的事件 并且 将 其 传递给 当前正在运行的应用程序的事件队列。然后 这项事件 会被事件循环 传递给 优先响应者物件。优先响应者物件 是 事件 被触发时 和 用户 交互的物件,比如 按钮物件、视图物件。如果 我们 编写了 代码 让 优先响应者 处理 这种类型的事件,那么 它 就会处理 这种类型的事件。处理完 某项事件后,响应者 有 两个选项:1、将 其 丢弃;2、将 其 传递给 响应链条中的下一个响应者。下一个响应者的地址 存储 在当前响应者物件所包含的变量nextResponder当中。如果 优先响应者 无法处理 一项事件,那么 这项事件 就传递给 下一个响应者,直到 这项事件 到达 能处理它的响应者 或者 到达 响应链条的末端,也就是 UIApplication类型的物件。UIApplication类型的物件 收到 一项事件后,也是 要么 处理,要么 丢弃。“
比如 有 一个视图物件,这个视图物件上 有 一个按钮物件。当用户 触摸 这个按钮物件时,作为优先响应者,这个按钮物件 就会收到 一项事件。如果 这个按钮物件 无法处理 这项事件,就会将 这项事件 传递给 视图物件。如果 视图物件 无法处理 这项事件,就会将 这项事件 传递给 视图控制器物件。以此类推。
应该注意的 是 当我们 在使用 响应链条时,一项事件 并不会自动地 从一个响应者 传递到 下一个响应者。如果 要将 一项事件 从一个响应者 传递到 下一个响应者,我们 必须编写 代码 才能办到。”