我们在开发过程中总会遇到如下场景:
1.tableviewcell(view)中的控件点击需要跳转到各种页面
2.在使用app或者开打app,需要处理远程通知的跳转
跳转总是需要CurrentViewController
在app中做跳转,我们总是需要获得一个可以ViewController来做转场动画,通常的场景就是正在展示的ViewController做push或者present,特别是在Self-Manager这种思想下,因为控件的self-manager之后需要handle事件,比如跳转
@implementation FDAvatarView (FDAvatarViewSelfManager)
// 为后一个页面的创建增加了个 UID 参数
- (void)selfManagedConfigureWithAvatarURL:(NSURL *)URL VIPInfo:(id)info UID:(NSString *)UID {
[self configureWithAvatarURL:URL VIPInfo:info tapped:^{
// 假设 App 结构是 Root -> TabBar -> Navigation -> ViewController
UITabBarController *tabBarControler = (id)[UIApplication.sharedApplication.delegate.window.rootViewController;
UINavigationController *navigationController = tabBarControler.selectedViewController;
// 创建用户信息 View Controller
FDUserProfileViewController *profileViewController = [FDUserProfileViewController viewControllerWithUID:UID];
[navigationController pushViewController:profileViewController animated:YES];
}];
}
@end
然而控件可能会出现在各种各样的ViewController中,如何获得当前的ViewController
获得CurrentViewController
demo地址:https://github.com/Sdoy/CurrentViewController
写一个继承自UIViewController的子类,就叫BaseViewController
@interface BaseViewController : UIViewController
@end
然后在BaseViewController中将self绑定到Application中的currentViewController属性
@implementation BaseViewController
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[UIApplication sharedApplication].currentViewController=self;
}
@end
恩,如何绑定?
为UIApplication写一个Category
@interface UIApplication (CurrentViewController)
@property (nonatomic, weak) UIViewController *currentViewController;
@end
.m文件
#import "UIApplication+CurrentViewController.h"
#import <objc/runtime.h>
@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了,调用起来是这样的
比如收到了远程通知:
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
//You can esay find out which view controller is on the screen here.
UIViewController *currentVC=[UIApplication sharedApplication].currentViewController;
NSLog(@"%@",currentVC);
}
或者在子控件做跳转:
-(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个宏定义,用起来更方便
#define CurrentVC [UIApplication sharedApplication].currentViewController
#define PushVC(ViewController) [[UIApplication sharedApplication].currentViewController.navigationController pushViewController:ViewController animated:YES]
#define PresentVC(ViewController)\
UINavigationController *nv=[[UINavigationController alloc]initWithRootViewController:ViewController];\
[[UIApplication sharedApplication].currentViewController presentViewController:nv animated:YES completion:nil]
为什么不直接hook,UIViewController的viewWillAppear:方法?
因为很多苹果的私有组件都是继承自UIViewController的,他们也许是没有nav的
如果在一些特殊情况下,没有经过ViewWillAppear方法
可以用[UIApplication topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController]方法来获取