1、关于UIResonder
是UIKit的一个抽象类,用于接收和处理事件。例如触摸事件,摇晃设备事件(运动事件)、输入文本事件等。UIVew、UIViewController、UIApplication等都是其子类。这些子类在必要时通过覆盖这些方法来实现事件发生时的自定义处理方式。
在事件发生时,如果是触摸事件,则系统会将事件发送给被触摸的视图去处理。而其他类型的事件则交由第一响应者负责处理。UIWindow包含一个firstResponder的属性,指向第一响应者。
例如点击UITextField,则其成为UIWindow的第一响应者,系统会将接下来收到的运动事件和功能控制事件(如输入文本)都交由firstResponder处理,UITextField成为firstResponder时会自动弹出键盘。
UITextField也可以主动发送becomeFirstResponder来激活键盘,对应地,UITextField不是firstResponder时键盘将自动消失,因此UITextField可以主动发送resignFirstResponder来隐藏键盘。
大部分UIView的子类对象并不需要成为firstResponder,例如UISlider,一般只需要处理触摸事件,即用户拖拽了滑块,不需要处理其他的事件。
2、响应对象链
UIResponder包含一个nextResponder指针,仍然指向一个UIRespond的子类对象,这种链表结构构成了响应对象链。如果一个UIResponder无法处理传给他的事件时,事件将沿着nextRespond一路往下传递,直到有UIResponder处理该事件,如果事件传递到UIApplication仍然无法处理,则被丢弃。
UIResponder中的默认实现是什么都不做,但UIResponder的直接子类(UIView,UIViewController等)的默认实现是将事件沿着responder 链继续nextResponder。所以在定制UIView子类的上述事件处理方法时,如果需要将事件传递给next responder,可以直接调用super的对应事件处理方法。
关于事件响应对象链的结构,官方文档的说明是:
The UIResponder class does not store or set the next responder automatically, instead returning nil by default. Subclasses must override this method to set the next responder. UIView implements this method by returning the UIViewController object that manages it (if it has one) or its superview (if it doesn’t); UIViewController implements the method by returning its view’s superview; UIWindow returns the application object, and UIApplication returns nil.
即:
- UIView的nextResponder属性,如果有管理此view的UIViewController对象,则为此UIViewController对象;否则nextResponder即为其superview。
- UIViewController的nextResponder属性为其管理view的superview。
- UIWindow的nextResponder属性为UIApplication对象。
- UIApplication的nextResponder属性为nil。
测试代码如下:
appDelegate.m文件中:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window=[[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
BNRDrawControllerViewController * vc=[[BNRDrawControllerViewController alloc] init];
[self.window setRootViewController:vc];
[application setApplicationIconBadgeNumber:2];
[self.window setBackgroundColor:[UIColor whiteColor]];
[self.window makeKeyAndVisible];
NSLog(@"address of window=%p",self.window);//0x7be8a140
NSLog(@"address of viewcontroller=%p",vc);//0x7bf88330
NSLog(@"address of application=%p",application);//0x7bf76a70
NSLog(@"address of view=%p",vc.view);//0x7bf88280
//viewController的nextResopnder指向其view的superview,即uiwindow
NSLog(@"address of viewcontroller next responder=%p",[vc nextResponder]);//0x7be8a140
//uiwindow的nextResponder指向application
NSLog(@"address of window next respond=%p",[self.window nextResponder]);//0x7bf76a70
//application的nextResponder指向nil??
NSLog(@"address of application next responder=%p",[application nextResponder]);//0x7c06e8c0
//view的nextResponder指向其viewController
NSLog(@"address of view next responder=%p",[vc.view nextResponder]);//0x7bf88330
//不直接属于UIViewController的UIView的nextResponder指向其superview
NSLog(@"address of view's subview next responder=%p",[vc.view.subviews[0] nextResponder]);//0x7bf88280
return YES;
}
其中vc.view.subviews[0] 是在ViewController中添加的一个subView:
-(void) loadView{
self.view=[[BNRDrawView alloc] initWithFrame:CGRectZero];
UIButton* button=[[UIButton alloc] initWithFrame:CGRectZero];
[self.view addSubview:button];
}