美文网首页
重写和监听iOS 导航栏自带的返回action事件

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

作者: 进击的iOS开发 | 来源:发表于2017-12-05 15:34 被阅读0次

    前言

    有的时候我们往往在没有重写系统自带按钮的情况下想监听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");
        }
    }
    

    相关文章

      网友评论

          本文标题:重写和监听iOS 导航栏自带的返回action事件

          本文链接:https://www.haomeiwen.com/subject/oygxixtx.html