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

最近一次做项目需求时,遇到这样一个需求,就是本来我们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. ASIOTutorial

    ASIOTutorialTutorial 1: Simple wgetTutorial 2: Synchronous HTTP ServerTutorial 3: Asynchrnous wgetTu ...

  2. Wormholes---poj3259(最短路 spfa 判断负环 模板)

    题目链接:http://poj.org/problem?id=3259 题意是问是否能通过虫洞回到过去: 虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts. 我们把虫洞看成是一条负权路,问 ...

  3. nginx中获取真实ip(转)

    原文:http://blog.csdn.net/a936676463/article/details/8961504 server { listen       80; server_name  lo ...

  4. 【spring mvc】扒一扒tomcat

    1.TOMCAT的目录 主要说一下webapps目录,WEB应用的目录结构:假设在$CATALINA_HOME/webapps下有helloapp的web应用 /helloapp:Web应用的根目录, ...

  5. Flask系列(七)Flask中的wtforms使用

    一.简单介绍flask中的wtforms WTForms是一个支持多个web框架的form组件,主要用于对用户请求数据进行验证. 安装: pip3 install wtforms 二.简单使用wtfo ...

  6. ASP.NET之报表--RDLC(一)---附源码

    听同事介绍到RDLC,之前有了解过报表,但是确实没什么放在心上.最近有空,就研究下了. 一.RDLC实现 1.步骤 (1)首先新建一个项目RDLCDemo (2)新建一个DataSet数据集,并且绑定 ...

  7. python webdriver 测试框架-数据驱动xml驱动方式

    数据驱动xml驱动的方式 存数据的xml文件:TestData.xml: <?xml version="1.0" encoding="utf-8"?> ...

  8. Errors occurred during the build. Errors running builder 'DeploymentBuilder' on project

    本文转自:http://www.phperz.com/article/14/1205/39544.html 本文向大家讲解了Myeclipse错误:Errors occurred during the ...

  9. source insight 4.0的基本使用方法(转)

    源:source insight 4.0的基本使用方法 source insight 4设置

  10. Vue学习笔记之Vue指令系统介绍

    所谓指令系统,大家可以联想咱们的cmd命令行工具,只要我输入一条正确的指令,系统就开始干活了. 在vue中,指令系统,设置一些命令之后,来操作我们的数据属性,并展示到我们的DOM上. OK,接下来我们 ...