iOS中一句代码解决倒计时问题

作者: HenryCheng | 来源:发表于2016-01-05 00:10 被阅读19568次

最近工作比较忙,然后最近也在尝试着翻译一篇关于CALayer非常详解的一篇文章,文章还是比较好也比较长的,等整理完了再发布出来吧。所以也没啥多余的时间写些东西,就先来分享一下开发中的一些小Tips吧。

一、倒计时问题


在开发中经常遇到倒计时倒计时问题,写一个Button,然后各种判断各种状态,好多代码感觉很乱,下面就分享一下,一句话解决倒计时问题的例子(当然不是万能的,只适合大部分普通的倒计时_)!
先看效果

倒计时按钮的效果

再看看我们的代码

//
//  ViewController.m
//  HWCountdownDemo
//
//  Created by HenryCheng on 16/1/4.
//  Copyright © 2016年 www.igancao.com. All rights reserved.
//

#import "ViewController.h"
#import "UIButton+countDown.h"

@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIButton *countdownBtn;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

}
- (IBAction)countdownBtnClick:(UIButton *)sender {
    [_countdownBtn startWithTime:5 title:@"获取验证码" countDownTitle:@"s" mainColor:[UIColor colorWithRed:84/255.0 green:180/255.0 blue:98/255.0 alpha:1.0f] countColor:[UIColor lightGrayColor]];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

这里主要的就是xib拉了一个button然后连接了它的属性和方法,我们可以看到就调用了

[_countdownBtn startWithTime:5 title:@"获取验证码" countDownTitle:@"s" mainColor:[UIColor colorWithRed:84/255.0 green:180/255.0 blue:98/255.0 alpha:1.0f] countColor:[UIColor lightGrayColor]];}

这一句代码,就完成了倒计时功能。
这里我写了一个category,里面代码是这样的

//
//  UIButton+countDown.m
//  LiquoriceDoctorProject
//
//  Created by HenryCheng on 15/12/4.
//  Copyright © 2015年 iMac. All rights reserved.
//

#import "UIButton+countDown.h"

@implementation UIButton (countDown)

- (void)startWithTime:(NSInteger)timeLine title:(NSString *)title countDownTitle:(NSString *)subTitle mainColor:(UIColor *)mColor countColor:(UIColor *)color {
    
    //倒计时时间
    __block NSInteger timeOut = timeLine;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    //每秒执行一次
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 1.0 * NSEC_PER_SEC, 0);
    dispatch_source_set_event_handler(_timer, ^{
        
        //倒计时结束,关闭
        if (timeOut <= 0) {
            dispatch_source_cancel(_timer);
            dispatch_async(dispatch_get_main_queue(), ^{
                self.backgroundColor = mColor;
                [self setTitle:title forState:UIControlStateNormal];
                self.userInteractionEnabled = YES;
            });
        } else {
            int allTime = (int)timeLine + 1;
            int seconds = timeOut % allTime;     
            NSString *timeStr = [NSString stringWithFormat:@"%0.2d", seconds];
            dispatch_async(dispatch_get_main_queue(), ^{
                self.backgroundColor = color;
                [self setTitle:[NSString stringWithFormat:@"%@%@",timeStr,subTitle] forState:UIControlStateNormal];
                self.userInteractionEnabled = NO;
            });
            timeOut--;
        }
    });
    dispatch_resume(_timer);
}

@end

关于这个方法的定义

//
//  UIButton+countDown.h
//  LiquoriceDoctorProject
//
//  Created by HenryCheng on 15/12/4.
//  Copyright © 2015年 iMac. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface UIButton (countDown)

/**
 *  倒计时按钮
 *
 *  @param timeLine 倒计时总时间
 *  @param title    还没倒计时的title
 *  @param subTitle 倒计时中的子名字,如时、分
 *  @param mColor   还没倒计时的颜色
 *  @param color    倒计时中的颜色
 */
- (void)startWithTime:(NSInteger)timeLine title:(NSString *)title countDownTitle:(NSString *)subTitle mainColor:(UIColor *)mColor countColor:(UIColor *)color;

@end

试想,如果你有多个界面用到这样的倒计时按钮,比如什么登录注册、修改密码啥的,直接调用一个方法,会不会很方便?
上面的Demo所有的代码可以在 这里 看到
当然,这里只是简单地自定义,你还可以在里面做更多的操作,比如加点动画什么的。之前写过Swift的一些倒计时的例子,如果你有兴趣,可以看看下面的效果

加动画的倒计时按钮
代码在这里可以看到

二、复合语句在 Objective-C 中的使用


之前在一篇文章中看到过一次介绍复合语句在iOS中的使用,这里跟大家分享一下。
比如我们一般写一个tableView一般都是向下面这种写法写的

        self.myTableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)) style:UITableViewStyleGrouped];
        self.myTableView.dataSource = self;
        self.myTableView.delegate = self;
        [self.view addSubview:self.myTableView];

使用复合语句的话就是把整个代码块放在{里面,看起来更清晰,如下

   self.myTableView = ({ UITableView *tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)) style:UITableViewStyleGrouped];
        tableView.dataSource = self;
        tableView.delegate = self;
        [self.view addSubview:tableView];
        tableView;
       });

其实上面两段代码意思完全一样,只不过写法不同罢了,第二段看起来更炫酷,快去试试吧!

相关文章

网友评论

  • 孤雁_南飞:怎么在后台也运行呀!
  • 97f52a50453b:我遇到个问题,就是我60s倒计时开始后,我马上退出倒计时界面,然后再进来,页面不能再显示倒计时的变化,但是计时器是正常运行的,这是怎么回事呢
  • 小花猫走路静悄悄:真机下,按home键退出APP,计时器就停止运行了。
  • 丶逝水流年:大神,问一下,我是从控制器1底部弹出的控制器2 uiviewcontroller ,然后我点击按钮 按钮倒计时中,我点击返回 回到控制器1 再进入控制器2 那么按钮的倒计时没了,我是用的你的分类方法,我要咋样搞才能出去再进来还显示倒计时啊
  • 9868256c0ec2: 但是题主,有个问题哦,在获取验证码,可以回退在进入,这个倒计时就归零了,会导致有人利用这个刷验证码哦。
    0d48debc0995:@HenryCheng 利用runloop Model 吗?
    HenryCheng:@Ju独一 这个吧一般是后台在判断的,做出相应处理,不过本地这儿做也可以,这个demo里面是没做这个处理的
  • 汉斯哈哈哈:在iOS7上无法更新title, 设置title时加上[button setNeedsLayout];,应该是apple bug
    HenryCheng:@汉斯哈哈哈 这个还没在iOS 7上试过,iOS 7好像有很多得特殊处理,比如你把一个button的title的字体设置为bold就会有问题,和iOS 8不一样,谢谢指正
  • 97cdad74b810:完全不行..你1秒卡住
  • 一个人的阳光:GCD用得挺溜的,哪里可以看到GCD的用法,感觉这方面还很弱,楼主是看书学的还是看苹果的GCD使用文档 :smiley:
  • __Jason__:怎么取消倒计时呢?
  • 不是谢志伟:学习了
  • Ennnnnn7:如果退出当前控制器 如何移除timer
  • 永远都能:@HenryCheng ViewController关闭了定时器还在跑哦,建议加上这个判断:
    if (timeOut <= 0||!weakSelf) {...};
  • 易明:感谢分享!
  • 78bd5ca7ec3f:谢谢 O(∩_∩)O
    HenryCheng:@meam 哈哈,对你有帮助就好
  • 我就叫土豆:测试了一下,调整为120S,但是按钮却显示00S->59S...也就是说大于60秒不能显示,显示也是从59秒开始倒计时...
    HenryCheng:@我就叫土豆 新的代码里面已经有了,使用weakself可以防止闭环,新的代码都优化了,你可以下载看看
    我就叫土豆:@HenryCheng github上面是swift版本的.我已经改好了.
    但是我看到评论中:
    编程的蚂蚁
    23 楼 · 2016.01.06 14:57
    另外那个block里面也不建议直接使用self,用__weak __typeof(&*self)weakSelf =self;替代会更完美.

    指的是修改所有的self吗?还是其他的改法
    HenryCheng:@我就叫土豆 是的,你是复制博客上的代码实验的吧,这个bug在很早之前就修复了,是我没有考虑到的,在我的github上你可以下载最新的代码,已经修复了这个问题,谢谢建议!
  • 硅谷小虾米:原来是将倒计时函数进行封装然后引用啊,我还以为类本身就带有这个方法
    HenryCheng:@124223 本身有这种肯定早就被拿出来用了。。。
  • Theyouth:记录
  • QingQueen:每次看你的博客都会收获良多,赞一个:+1:
    HenryCheng:@ASpume 谢谢支持 :blush:
  • pengrain:我们项目里面有个倒计时功能,类似于彩票开奖的倒计时,倒计时时间很长,而且倒计时的个数也很多,开始用gcd来写这个倒计时 发现一下子点开后十几个线程都在跑,还停不下来 瞬间奔溃
  • I_m赵昊:楼主为何开这么多线程,能指点下么
  • d61a445df347:楼主 我用 xib 拉的button 会有闪动的效果 qq 471727371
    HenryCheng:@long855 因为你用代码写的时候写的是custom的吧,xib拖的时候默认的是system,所以他会出现闪动
    HenryCheng:@long855 因为你的button是system的,改成custom的就好
    d61a445df347:@long855
    不用xib 直接创建的没有闪动
  • 瑾仁:为甚么会有这么多线程在里面?它实现的效果与定时器实现效果有什么区别麽?
  • 柚子橙黄:复合语句,get:kissing_heart:
    HenryCheng:@iOS卡卡_微博 :relaxed:
  • _Shj:啥是GCC啊 ?
    :relieved:
    HenryCheng:@SShj :blush: www.baidu.com
  • 编程的蚂蚁:另外那个block里面也不建议直接使用self,用__weak __typeof(&*self)weakSelf =self;替代会更完美.
    霖溦:@编程的蚂蚁 gcd以及系统动画的block都没有必要weak,系统会将该block置空
    我就叫土豆:@编程的蚂蚁 蚂蚁哥,是需要将block里面的所有的self 改成 :__weak __typeof(&*self)weakSelf =self;这个吗?还是怎么改?
    HenryCheng:@编程的蚂蚁 嗯,使用weak能确保不会Retain Cycle,更合理一些 :+1:
  • 编程的蚂蚁:写的不错,受教了,有一点我觉得有点不太妥当,int seconds = timeOut % 60;这句话,最好改成
    int allTime = (int)timeLine+1; int seconds = timeOut % allTime;这两句,这样倒计时就可以更通用了,只是建议 :blush:
    HenryCheng:@编程的蚂蚁 谢谢你的意见 :clap:
  • Fe_Zn:如果用weak 修饰tableView ,用复合语句的话会有⚠,怎么解决呢?
    HenryCheng:@JsonChan 你用weak跟用不用复合语句没有关系。。。。。。
    Fe_Zn:@HenryCheng 对的,object will be release after assignment..不过运行中并没有什么问题,只是单纯看那个⚠️有点不爽... :joy: :joy:
    HenryCheng:@JsonChan 警告是分配完将会被释放?
  • 42b702b6b0eb:复合写法有点意思
  • 07a0b9addc9e:复合语句的最后一行tableView是什么意思。release吗?
    HenryCheng:@疾风哥哥 不是,复合语句最后一个语句的值就是跟返回值差不多的意思,比如这里self.myTableView = 整个复合语句最后一个语句,也就是tableView
  • johnmuu:get到了😁
    HenryCheng:@johnmuu :+1:
  • 667a69f9a9e1:不想不错
    HenryCheng:@667a69f9a9e1 :pray:
  • 花前月下:涨姿势了。 学到了复合语句。
    HenryCheng:@花前月下 :sunglasses:
  • 卖艺小青年o0:开拓思维
  • Zz7777777:不错
  • 96dfced25580:复合写法很不错,尤其是在自定义复杂view的时候,能够区分开来,不过现在都习惯自己分隔几行来区分各个子view的初始化,知道得太晚了 :sob:
    sclcoder:@HenryCheng 一般我都是懒加载写在get方法里, 复合写法也不错
    HenryCheng:@仲系xbb 能意识到晚的其实都不晚 :blush:
  • b09e41988821:留个脚印,code已带走:smile:
  • AdhereDamon:为什么添加那么多线程呢!
    张智杰:@KWK 在子线程里计算时间,在主线程里更新UI
    AdhereDamon:@lan941025 定时器默认就是开启一个线程的,但博主这么写为什么,具体我也不懂!
    瑾仁:@KWK 我也想问这个问题?难道定时器不能实现这个效果麽?
  • hcname:简单的就是好
  • 66f184ef79d3:完全被楼主的标题骗进来了,楼主好样的:+1:
  • 纯洁的小袋子:不错,学习了
  • Mokyz:说好的一句话解决呢? :joy:
    HenryCheng:@Mokz 调用的时候就是一句代码啊😓
  • 曾樑:这个实用的
    HenryCheng:@曾樑 嗯,对一般的倒计时问题足够的

本文标题:iOS中一句代码解决倒计时问题

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