前言
当我们点击屏幕的时候,就产生了一个点击事件,那程序是如何知道这个点击事件应该由谁来处理?
响应者
在iOS中,能够响应事件的就是响应者,而所有响应者都是UIResponser
的子类,例如:UIView
、UIButton
、UIControl
、UIWindow
、UIViewController
、AppDelegate
、UIApplication
以及它们的子类。
UIResponder
声明了各种点击事件的处理,比如点击,按压,移动等。
响应链
响应链就是响应者都连接一起的一个链条的层级关系,说是链条其实更类似树结构。
这个链条从程序开始运行时就建立并不断将响应者链接进来。
我们都知道程序运行后,UIApplication
会生成一个单例,并与AppDelegate
进行关联。而AppDelegate
就作为整个响应链的根建立存在,接着UIApplication
的单例就会作为响应者链接在根上,即[UIApplication sharedApplication].nextResponser = AppDelegate
。
当任何一个UIWindow
被创建时,UIWindow
都会自动链接在UIApplication
的单例上,即把UIWindow
的nextResponser
设置为UIApplication
的单例。
当UIWindow
设置rootViewController
时,rootViewController
就会链接在UIWindow
上。
UIViewController
初始化loadView
时, UIViewController
的view
就会链接在UIViewController
上。
addSubView
的操作过程中,subView
的nextResponser
会被设置为superView
。
举例验证环节:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window.rootViewController = [[ViewController alloc] init];
[self.window makeKeyAndVisible];
return YES;
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIView *view = [[UIView alloc] init];
[self.view addSubview:view];
UILabel *label = [[UILabel alloc] init];
[view addSubview:label];
[self logOutResponderChain:label];
}
- (void)logOutResponderChain:(UIResponder *)responder {
UIResponder *nextResponder = responder.nextResponder;
NSLog(@"%@ -> ", NSStringFromClass([responder class]));
while (nextResponder) {
NSLog(@"%@ -> ", NSStringFromClass([nextResponder class]));
nextResponder = nextResponder.nextResponder;
}
NSLog(@"*");
}
打印结果如下:
UILabel -> UIView -> UIView -> ViewController ->
UIDropShadowView -> UITransitionView ->
UIWindow -> UIWindowScene -> UIApplication -> AppDelegate -> *
传递链
通过上文,我们已经知道了响应链是如何建立的,而建立响应链就是为了让事件能找到对应的处理者,而找到处理者的过程称之为事件的传递链。
这里先给出结论:
(1)当用户点击屏幕触发事件,系统硬件进程会获取到这个事件,将事件简单处理封装后存到系统中,系统接着将事件转交到UIApplication
管理的事件队列中。(这一部分涉及RunLoop和端口通信)
(2)UIApplication
会从事件队列中取出最前面的事件,并将事件顺着响应链分发下去,寻找合适的控件进行处理。
(3)