美文网首页
IOS-如何优雅地拦截按钮事件(判断是否需要登录)

IOS-如何优雅地拦截按钮事件(判断是否需要登录)

作者: leonardni | 来源:发表于2017-08-07 15:58 被阅读81次

    关于这个标题,起因是这样的。

    最近一次做项目需求时,遇到这样一个需求,就是本来我们App是必须注册或者第三方登录才可以使用,现在希望不登录也可以浏览App里面的内容,只是在需要的时候才提示登录,并且在用户没有登录的情况下,用户选择并登录成功了,程序需自动完成用户操作登录前的操作。比如购买商品时没有登录,用户登录成功后,直接跳转至订单确认页面。

    在接到这个需求时,我们的App功能已经很多了,评估了下这个需求,发现App里面很多功能是需要登录才可以操作,比如关注用户、购买商品、私信聊天、评论等等,而且这些功能的入口也比较多。

    这么多的地方我们都要去写判断的代码显然是不科学的,那么有没有简单点的方式呢?怎么避免我们去做苦力活呢?????????????

    于是,进一步分析,发现这些功能大部分都是用户主动通过点击按钮来触发下一步操作。此时,我们把关注点移到按钮UIButton上。

    最开始想到的办法是自定义一个button,让所有需要登录操作的按钮继承这个按钮,然后,在这个按钮里面拦截自身事件进一步处理。但是,发现这么做还是需要改大量的代码。接着想到用类别来做,这样直接给按钮增加一个BOOL属性,设置为YES的按钮视为需要做登录才可以操作的按钮。然后,对于需要登录操作的按钮,在分类里面拦截其点击事件,并记录target和action,然后先判断是否登录:如果没有登录则丢弃其target和action,并且提示用户登录;如果用户已经登录或者登录成功了,则继续让target执行action,这样完美解决我们的需求,也只需要很少的代码即可搞定。
    这个方案看似很不错,不过在实际做的时候还是走了弯路。一开始,我们想从下面方法入手

    - (void)addTarget:(nullableid)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents
    

    但是发现根本就不能实现。经过查找,找到了下面这个方法:

    - (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
    

    关于这个方法,苹果给了如下解释:

    send the action. the first method is called for the event and is a point at 
    which you can observe or override behavior. it is called repeately by the 
    second.
    
    - (void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
    {    if (self.checkLogin)
        {        self.selector = NSStringFromSelector(action);        self.objClass = target;
            [self checkIsLogin];
        }    else
        {
            [super sendAction:action to:target forEvent:event];
        }
    }
    - (void)checkIsLogin
    {
        __weak typeof(self) weakSelf = self;
        [LoginManager checkLoginSuccess:^{
            SEL sel = NSSelectorFromString(weakSelf.selector);        if ([weakSelf.objClass respondsToSelector:sel])
            {            if ([weakSelf.selector hasSuffix:@":"])
                {
                    objc_msgSend(weakSelf.objClass, sel, self);
                }            else
                {
                    objc_msgSend(weakSelf.objClass, sel);
                }
            }
        }];
    }
    

    简单解释下这段代码:

    当按钮事件执行时会走sendAction:to:forEvent:这个方法,于是,我们在这个方法里面,先判断该按钮是否需要登录后再操作,如果需要,阻断事件传递,并记录下按钮的action和target,然后判断是否登录了,如果已经登录或者用户登录成功了,那么再调用objc_msgSend(self.objClass, self.selector)去实现按钮事件,如果用户放弃登录或者登录失败,则不做处理。

    实现了上面的方法之后,我们只需要找出那些按钮事件需要登录后才能操作,然后,设置按钮的checkLogin = YES即可,这样是不是省了很多不必要的代码。

    到此,上面的实现已经解决了所有按钮点击需要判断登录的操作。还有些是上述方式解决不了的,则使用LoginManager单独处理下,幸运的是,几乎很少地方需要单独处理。

    通过这个案例:一方面巩固了对sendAction:to:forEvent:这个方法的理解;另一方面在做需求的时候一定要发散思维,找到更合理的解决方法。

    欢迎大家留言讨论,如果你有更好地方法,欢迎分享!

    相关文章

      网友评论

          本文标题:IOS-如何优雅地拦截按钮事件(判断是否需要登录)

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