重写和监听iOS 导航栏自带的返回action事件

2017-12-05  本文已影响0人  进击的iOS开发

前言

有的时候我们往往在没有重写系统自带按钮的情况下想监听back事件,做一些事情.举个栗子:我常常解决程序的内存泄漏,最好的办法是找得泄漏的地方修复(废话),但是往往可能各种原因,你到不到问题的所在,逻辑过于复杂或者n代单传老代码,或者时间不允许,我常常采用主动断开的方式去解决循环引用,最好的时机就是back按钮响应的时候,去断开一些不用的引用.废话不多说了.

思路:按钮肯定会有方法响应,我们只要知道系统方法就好了!

继承UINavigationController 重写respondsToSelector 方法,点击back断点在其中,得到了navigationBar:shouldPopItem: 函数.是他就是他,小哪吒!


找到响应方法.png

1.重写

然后高兴的去重写

- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem*)item {
    
 return [super performSelector:@selector(navigationBar:shouldPopItem:) withObject:navigationBar withObject:item];
}
直接重新的问题.png

很好,这样写==完全不对==,会变成死循环.才疏学浅,哪位老司机看到我这个疑惑记得带我上车!!!

我就拿着函数名去百度,找到这位仁兄文章,很好,可以用了,我简化一下

- (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");
    }
}
上一篇 下一篇

猜你喜欢

热点阅读