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

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

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

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

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

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

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

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

1
- (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.

这正是我们要找的方法,于是我们重写此方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (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-如何优雅地拦截按钮事件(判断是否需要登录)的更多相关文章

  1. springMvc实现拦截特定请求判断用户是否登录

    流程: 新建一个拦截器,配置拦截哪些,放行哪些 在spring servrt中配置拦截器 <!--配置拦截器--> <mvc:interceptors> <!--登录拦截 ...

  2. 拦截iOS系统导航栏返回按钮事件-三种方法

    方法一:在dealloc里面书写监听事件,因为只有pop才会调用dealloc,push不会掉用 - (void)dealloc {YLLog(@"123"); } 方法二:在- ...

  3. IOS第四天(5:创建备份区按钮和判断结果)

    创建备份区按钮和判断结果 /** 创建备选区按钮 */ - (void)createOptionButtons:(HMQuestion *)question { // 问题:每次调用下一题方法时,都会 ...

  4. iOS代码实现:创建按钮,绑定按钮事件,读取控件值

    // // main.m // Hello // // Created by lishujun on 14-8-28. // Copyright (c) 2014年 lishujun. All rig ...

  5. iOS 用RunTime来提升按钮的体验

    用RunTime来提升按钮的体验 载请标明出处:http://blog.csdn.net/sk719887916/article/details/52597388,作者:Ryan 经常处理按钮问题都是 ...

  6. iOS头条新闻App、自动布局、省市区联动、登录按钮动画、Alert弹框效果等源码

    iOS精选源码 LEEAlert -- 优雅的Alert ActionSheet 登录按钮 省市区三级联动 JHViewCorner - 一行代码搞定圆角 JHFrameLayout - 一行代码实现 ...

  7. asp.net中用回车代替按钮事件

    第一步,先编写简单的页面代码,这里我们只需要一个按钮就足够了.当然,还有按钮事件. <html> <head> <title>测试绑定enter</title ...

  8. Android中Touch事件分析--解决HorizontalScrollView滑动和按钮事件触发问题

    之前写过关于HorizontalScrollView滑动和按钮事件触发问题,但是不能所有的情况,最近几天一直在想这个问题,今天有一个比较好的解决思路,最终应用在项目里面效果也很好,首先说明一下功能: ...

  9. Java知多少(82)标签、按钮和按钮事件简介

    标签和按钮也许是图形界面中最常见的两种组件,按钮又总是与激发动作事件有关. 标签 标签(JLabel)是最简单的Swing组件.标签对象的作用是对位于其后的界面组件作说明.可以设置标签的属性,即前景色 ...

随机推荐

  1. 向Docx4j生成的word文档中添加布局--第二部分

    原文标题:Adding layout to your Docx4j-generated word documents, part 2 原文链接:http://blog.iprofs.nl/2012/1 ...

  2. Python开发【数据结构】:算法(一)

    算法基础 1.什么是算法? 算法(Algorithm):一个计算过程,解决问题的方法 2.复习:递归 递归的两个特点: 调用自身 结束条件 两个重要递归函数的对比: # 由大到小 def func3( ...

  3. jquery序列化表单以及回调函数的使用

    在开发项目中.将前台的值传给后台,有时的JSP表单中的值有一两个,也有所有的值,假设这时一个个传,必然不是非常好的办法,所以使用jQuery提供的表单序列化方法,能够非常好的解决问题.同一时候能够封装 ...

  4. android唯一设备标识、设备号、设备ID的获取方法

    ##如何获取Android设备唯一ID? ###问题 每一个android设备都有唯一ID吗?如果有?怎么用java最简单取得呢? ###回答1(最佳) 如何取得android唯一码? 好处: 1.不 ...

  5. PHP之设计模式

    https://blog.csdn.net/self_realian/article/details/78228733 掌握PHP各类设计模式,具备设计纯面向对象框架和系统能力是非常有必要的.给大家一 ...

  6. Django REST framework 之 API认证

    RESTful API 认证 和 Web 应用不同,RESTful APIs 通常是无状态的, 也就意味着不应使用 sessions 或 cookies, 因此每个请求应附带某种授权凭证,因为用户授权 ...

  7. [py]django重置密码

    django的admin用户被我多动症一样的测试,给密码弄丢了,需要重置. 从数据库重置的可能性为0,因为django对于密码有保护策略.考虑从运行程序的地方进行重置: 1.在程序的文件夹下,执行这样 ...

  8. eclipse中gradle插件安装

    help===>install software===>http://download.eclipse.org/buildship/updates/e46/releases/2.x/

  9. BZOJ3944: Sum(杜教筛模板)

    BZOJ3944: Sum(杜教筛模板) 题面描述 传送门 题目分析 求\(\sum_{i=1}^{n}\mu(i)\)和\(\sum_{i=1}^{n}\varphi(i)\) 数据范围线性不可做. ...

  10. CSU 1968 Permutation Descent Counts

    http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1968 题意:对于任一种N的排列A,定义它的E值为序列中满足A[i]>A[i+1]的数的个 ...