我们在开发过程中总会遇到如下场景:
1.tableviewcell(view)中的控件点击需要跳转到各种页面
2.在使用app或者开打app,需要处理远程通知的跳转
跳转总是需要CurrentViewController
在app中做跳转,我们总是需要获得一个可以ViewController来做转场动画,通常的场景就是正在展示的ViewController做push或者present,特别是在Self-Manager这种思想下,因为控件的self-manager之后需要handle事件,比如跳转
1 | @implementation FDAvatarView (FDAvatarViewSelfManager) |
然而控件可能会出现在各种各样的ViewController中,如何获得当前的ViewController
获得CurrentViewController
demo地址:https://github.com/Sdoy/CurrentViewController
写一个继承自UIViewController的子类,就叫BaseViewController1
2@interface BaseViewController : UIViewController
@end
然后在BaseViewController中将self绑定到Application中的currentViewController属性1
2
3
4
5
6
7@implementation BaseViewController
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[UIApplication sharedApplication].currentViewController=self;
}
@end
恩,如何绑定?
为UIApplication写一个Category1
2
3@interface UIApplication (CurrentViewController)
@property (nonatomic, weak) UIViewController *currentViewController;
@end
.m文件1
2
3
4
5
6
7
8
9
10
11
12
@implementation UIApplication (CurrentViewController)
-(void)setCurrentViewController:(UIViewController *)currentViewController
{
objc_setAssociatedObject(self, @selector(currentViewController), currentViewController, OBJC_ASSOCIATION_ASSIGN);
}
-(UIViewController *)currentViewController
{
return objc_getAssociatedObject(self, _cmd);
}
@end
至此,只要你的ViewController都是继承自BaseViewController,你就可以在任何地方都能拿到CurrentViewController了,调用起来是这样的
比如收到了远程通知:
1 | - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { |
或者在子控件做跳转:1
2
3
4
5
6
7
8-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//if you want to go another view controller when you touch this view
//you don't need create a delegate to let the display or some view controller to perform SEL
NSLog(@"%@",[UIApplication sharedApplication].currentViewController);
AnotherViewController *another=[[AnotherViewController alloc]init];
[[UIApplication sharedApplication].currentViewController.navigationController pushViewController:another animated:YES];
}
而且还写了3个宏定义,用起来更方便1
2
3
4
5
UINavigationController *nv=[[UINavigationController alloc]initWithRootViewController:ViewController];\
[[UIApplication sharedApplication].currentViewController presentViewController:nv animated:YES completion:nil]
为什么不直接hook,UIViewController的viewWillAppear:方法?
因为很多苹果的私有组件都是继承自UIViewController的,他们也许是没有nav的.
编后:
首先感谢sunnyxx抽时间看了文章以及分享的如何获取current的代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16@implementation UIViewController (FDTopViewController)
+ (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
if ([rootViewController isKindOfClass:[UITabBarController class]]) {
UITabBarController* tabBarController = (UITabBarController*)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
} else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
UINavigationController* navigationController = (UINavigationController*)rootViewController;
return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
} else if (rootViewController.presentedViewController) {
UIViewController* presentedViewController = rootViewController.presentedViewController;
return [self topViewControllerWithRootViewController:presentedViewController];
} else {
return rootViewController;
}
}
@end
的确,这样的方法更利于老项目的修改,而且从使用方便的角度讲比文中提到的好太多了,虽然可能多调几次方法,和多走几次if判断,但基本不会成为app性能的瓶颈。