重写和监听iOS 导航栏自带的返回action事件
2017-12-05 本文已影响0人
进击的iOS开发
前言
有的时候我们往往在没有重写系统自带按钮的情况下想监听back事件,做一些事情.举个栗子:我常常解决程序的内存泄漏,最好的办法是找得泄漏的地方修复(废话),但是往往可能各种原因,你到不到问题的所在,逻辑过于复杂或者n代单传老代码,或者时间不允许,我常常采用主动断开的方式去解决循环引用,最好的时机就是back按钮响应的时候,去断开一些不用的引用.废话不多说了.
思路:按钮肯定会有方法响应,我们只要知道系统方法就好了!
继承UINavigationController 重写respondsToSelector 方法,点击back断点在其中,得到了navigationBar:shouldPopItem: 函数.是他就是他,小哪吒!

1.重写
然后高兴的去重写
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem*)item {
return [super performSelector:@selector(navigationBar:shouldPopItem:) withObject:navigationBar withObject:item];
}

很好,这样写==完全不对==,会变成死循环.才疏学浅,哪位老司机看到我这个疑惑记得带我上车!!!
我就拿着函数名去百度,找到这位仁兄文章,很好,可以用了,我简化一下
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem*)item {
if([self.viewControllers count] < [navigationBar.items count]) {
return YES;
}
//使用代理或者通知
[self popViewControllerAnimated:YES];
return NO;
}
基本测试通过了,但是这样写也不是很方便,需要继承,我本意是想监听一下就好,对,我想起了可以用hook的方式
2.监听
hook不太会用的可以看利用Objective-C运行时hook函数的三种方法
监听一下,发个消息出来,也能降低耦合度,采用分类里load方法加载,不用手动调用,也无需继承.
直接上代码
h文件
#import <UIKit/UIKit.h>
#define KYYEObserveNavBackNoti @"KYYEObserveNavBackNoti"
@interface UINavigationController (YYEObserveNavBack)
@end
m文件
#import "UINavigationController+YYEObserveNavBack.h"
#import <objc/runtime.h>
@implementation UINavigationController (YYEObserveNavBack)
+(void)load {
[super load];
[self hook];
}
void exchangeMethod(Class aClass,Class bClass, SEL oldSEL, SEL newSEL) {
Method oldMethod = class_getInstanceMethod(aClass, oldSEL);
assert(oldMethod);
Method newMethod = class_getInstanceMethod(bClass, newSEL);
assert(newMethod);
method_exchangeImplementations(oldMethod, newMethod);
}
+ (void)hook {
exchangeMethod([self class],
[self class],
@selector(navigationBar:shouldPopItem:),
@selector(hook_navigationBar:shouldPopItem:));
}
- (void)hook_navigationBar:(id)arg1 shouldPopItem:(id)arg2 {
[[NSNotificationCenter defaultCenter] postNotificationName:KYYEObserveNavBackNoti object:self.childViewControllers.lastObject];
[self performSelector:@selector(hook_navigationBar:shouldPopItem:) withObject:arg1 withObject:arg2];
}
@end
最后使用,大家发现问题或者有更好的方式实现请告诉我,不胜感激
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(observerNavBackClick:) name:KYYEObserveNavBackNoti object:nil];
}
- (void)observerNavBackClick:(NSNotification *)noti {
id aa = noti.object;
// 最好判断一下 不然这个控制器如果发生内存泄漏 这句会经常执行
if (self == aa) {
NSLog(@"do something");
}
}