IOS开发中响应者链
在IOS开发中,有时候会遇到如下情况:在页面1上有一个RedView,在RedView上有一个GreenView,在GreenView上有一个button,这些view的创建代码如下:
1、AppDelegate.m
1 // 2 // AppDelegate.m 3 // 响应者链 4 // 5 // Created by mac on 16/5/10. 6 // Copyright © 2016年 mzw. All rights reserved. 7 // 8 9 #import "AppDelegate.h" 10 #import "RootViewController.h" 11 12 @interface AppDelegate () 13 14 @end 15 16 @implementation AppDelegate 17 18 19 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 20 21 22 self.window = [[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds]; 23 self.window.backgroundColor = [UIColor lightGrayColor]; 24 [self.window makeKeyAndVisible]; 25 26 27 RootViewController *rootVC = [[RootViewController alloc]init]; 28 UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:rootVC]; 29 self.window.rootViewController = nav; 30 31 return YES; 32 } 33 34 @end
2、RootViewController.m
1 // 2 // RootViewController.m 3 // 响应者链 4 // 5 // Created by mac on 16/5/10. 6 // Copyright © 2016年 mzw. All rights reserved. 7 // 8 9 #import "RootViewController.h" 10 #import "FirstVCViewController.h" 11 #import "RedView.h" 12 13 @interface RootViewController () 14 15 @end 16 17 @implementation RootViewController 18 19 - (void)viewDidLoad { 20 [super viewDidLoad]; 21 self.view.backgroundColor = [UIColor grayColor]; 22 RedView *redVC = [[RedView alloc]initWithFrame:CGRectMake(80, 80, 200, 200)]; 23 [self.view addSubview:redVC]; 24 25 } 26 27 @end
3、RedView.m
1 // 2 // RedView.m 3 // 响应者链 4 // 5 // Created by mac on 16/5/10. 6 // Copyright © 2016年 mzw. All rights reserved. 7 // 8 9 #import "RedView.h" 10 #import "GreenView.h" 11 12 @implementation RedView 13 14 -(instancetype)initWithFrame:(CGRect)frame{ 15 self = [super initWithFrame:frame]; 16 if (self) { 17 self.backgroundColor = [UIColor redColor]; 18 GreenView *grennView = [[GreenView alloc]initWithFrame:CGRectMake(50 , 50, 100,100)]; 19 [self addSubview:grennView]; 20 21 } 22 return self; 23 } 24 25 @end
4、GreenView.m
1 // 2 // GreenView.m 3 // 响应者链 4 // 5 // Created by mac on 16/5/10. 6 // Copyright © 2016年 mzw. All rights reserved. 7 // 8 9 #import "GreenView.h" 10 #import "FirstVCViewController.h" 11 #import "UIView+ViewController.h" 12 13 @implementation GreenView 14 15 -(instancetype)initWithFrame:(CGRect)frame{ 16 17 self = [super initWithFrame:frame]; 18 if (self) { 19 self.backgroundColor = [UIColor greenColor]; 20 UIButton *myBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 10, 80, 40)]; 21 myBtn.backgroundColor = [UIColor orangeColor]; 22 [myBtn setTitle:@"导航按钮" forState:UIControlStateNormal]; 23 [myBtn addTarget:self action:@selector(myBtnAction:) forControlEvents:UIControlEventTouchUpInside]; 24 [self addSubview:myBtn]; 25 } 26 27 return self; 28 } 29 30 31 -(void)myBtnAction :(UIButton*)sender{ 32 33 FirstVCViewController *firstVC = [[FirstVCViewController alloc]init]; 34 [self.viewController.navigationController pushViewController:firstVC animated:YES]; 35 36 } 37 38 @end
这时候我们想在GreenView.m中实现点击myBtn之后跳转到FirstVCViewController的实体firstVC,但发现其实我们写不了第34行,因为在myBtnAction方法中,self指的是GreenView的实例,而GreenView的实例greenView是没有.navigationController方法的,这就需要通过View的从属关系去找到grennView的响应者redView,然后找到redView的响应者RootVC。RootVC才有.navigationController的方法,这样就可以实现点击按钮跳转到另一个ViewController了。实现方式如下,给UIView使用Category扩展一个方法,方法名字叫viewController,也就是找一个UIView对象的所属的ViewController对象,viewController类别实现如下:
1、UIView+ViewController.h中:
1 // 2 // UIView+ViewController.h 3 // Project-WXWeibo26 4 // 5 // Created by keyzhang on 14-9-29. 6 // Copyright (c) 2014年 keyzhang. All rights reserved. 7 // 8 9 #import <UIKit/UIKit.h> 10 11 @interface UIView (ViewController) 12 13 - (UIViewController *)viewController; 14 15 @end
2、UIView+ViewController.m中:
1 // 2 // UIView+ViewController.m 3 // Project-WXWeibo26 4 // 5 // Created by keyzhang on 14-9-29. 6 // Copyright (c) 2014年 keyzhang. All rights reserved. 7 // 8 9 #import "UIView+ViewController.h" 10 11 @implementation UIView (ViewController) 12 13 - (UIViewController *)viewController 14 { 15 UIResponder *next = self.nextResponder; 16 do { 17 if ([next isKindOfClass:[UIViewController class]]) { 18 return (UIViewController *)next; 19 } 20 21 next = next.nextResponder; 22 } while (next != nil); 23 24 return nil; 25 } 26 27 @end
方法的核心就是去判断一个UIView对象的响应者所属的类是不是UIViewController类,如果不是的话就继续找它的响应者的响应者,直到找到响应者是UIViewController为止。