• 分类

  • 重置

Swift实现倒计时5秒功能

    一般在项目的“引导页”有个功能,倒计时5秒结束后,然后可以允许用户点击跳过按钮跳过引导页。同样在“登录”和“注册”页面也有类似功能,发送验证码后,计时60秒后才允许用户再次请求重新发送验证码。

    计时方式一(sleep + performSelector)

    通过调用sleep(1)阻塞线程的方式来达到目的

    
    import UIKit
     
    class GAPublishViewController: GABaseViewController {
     
     var jumpBut = UIButton(frame: CGRect(x: 15, y: 64, width: 80, height: 40));
     var limitTime: Int = 5+1;
     
     override func viewDidLoad() {
      super.viewDidLoad()
      setupJumpButton();
      startCountDown();
     }
     
     func setupJumpButton() {
      view.addSubview(jumpBut);
      jumpBut.setTitle("跳过(5S)", for: .normal);
      jumpBut.setTitleColor(UIColor.red, for: .normal);
      jumpBut.addTarget(self, action: #selector(tapJumpAction(sender:)), for: .touchUpInside);
     }
     
     @objc func tapJumpAction(sender: Any) {
      let but = sender as! UIButton;
      let text = but.titleLabel?.text ?? "";
      if (text == "跳过") {
       print("点击“跳过”");
      }
     }
     
     // MARK: 定时方式一
     
     func startCountDown() {
      performSelector(inBackground: #selector(countDownThread), with: nil)
     }
     
     @objc func countDownThread() {
      let timeCount = limitTime;
      for _ in 0..<timeCount {
       limitTime = limitTime - 1;
       self.performSelector(onMainThread: #selector(updateJumpBtn), with: self, waitUntilDone: true)
       sleep(1);
      }
     }
     
     @objc func updateJumpBtn() {
      if (limitTime <= 0) {
       jumpBut.setTitle("跳过", for: .normal);
      } else {
       jumpBut.setTitle("跳过" + "(\(limitTime)S)", for: .normal);
      }
     }
     
    }

    计时方式二(sleep + GCD)

    与上面的方式一类似

    
     // MARK: 定时方式二
     
     func startCountDown() {
      // 将任务添加到队列,以异步的方式执行
      DispatchQueue.global().async { [weak self] in
       self?.countDownThread();
      }
     }
     
     func countDownThread() {
      let timeCount = limitTime;
      for _ in 0..<timeCount {
       limitTime = limitTime - 1;
       // 主线程刷新UI
       DispatchQueue.main.async { [weak self] in
        self?.updateJumpBtn();
       }
       sleep(1);
      }
     }
     
     func updateJumpBtn() {
      if (limitTime <= 0) {
       jumpBut.setTitle("跳过", for: .normal);
      } else {
       jumpBut.setTitle("跳过" + "(\(limitTime)S)", for: .normal);
      }
     }

    计时方式三(Timer)

    
    // MARK: 定时方式三
     
     var limitTime: Int = 5;
     var timer: Timer?;
     
     func startCountDown() {
      // 初始化定时器
      timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(updateJumpBtn), userInfo: nil, repeats: true);
      
      /*
      // 避免timer在列表时,滑动时timer会暂停。 将timer放在另外一个线程中,然后开启这个线程的runloop。
      DispatchQueue.global().async { [weak self] in
       self?.timer = Timer.scheduledTimer(timeInterval: 1.0, target: self as Any, selector: #selector(self?.countDownThread), userInfo: nil, repeats: true);
       RunLoop.current.run();
      }
       */
     }
     
     @objc func countDownThread() {
      // 主线程刷新UI
      DispatchQueue.main.async { [weak self] in
       self?.updateJumpBtn();
      }
     }
     
     @objc func updateJumpBtn() {
      limitTime = limitTime - 1;
      if (limitTime <= 0) {
       jumpBut.setTitle("跳过", for: .normal);
       /*
       // 暂停定时器
       timer?.fireDate = Date.distantFuture;
       // 继续定时
       timer?.fireDate = NSDate.init() as Date;
       // 暂停定时器3秒
       timer?.fireDate = Date.init(timeIntervalSinceNow: 3.0);
        */
       // 停止定时器
       timer?.invalidate();
      } else {
       jumpBut.setTitle("跳过" + "(\(limitTime)S)", for: .normal);
      }
     }

    计时方式四(GCD)

    
    // MARK: 定时方式四
     
     var limitTime: Int = 5+1;
     // 在global线程里创建一个时间源
     let codeTimer = DispatchSource.makeTimerSource(queue: DispatchQueue.global());
     
     func startCountDown() {
      // 设定这个时间源是每秒循环一次,立即开始
      codeTimer.schedule(deadline: .now(), repeating: .seconds(1));
      // 设定时间源的触发事件
      codeTimer.setEventHandler(handler: {
       // 主线程刷新UI
       DispatchQueue.main.async { [weak self] in
        self?.updateJumpBtn();
       }
      })
      // 判断是否取消,如果已经取消了避免调用resume()方法导致的崩溃
      if codeTimer.isCancelled {
       return;
      }
      // 启动时间源
      codeTimer.resume();
     }
     
     func updateJumpBtn() {
      limitTime = limitTime - 1;
      if (limitTime <= 0) {
       jumpBut.setTitle("跳过", for: .normal);
       // 暂停计时。暂停之后,再次开始计时(startCountDown())接着上次暂停进行计时
       codeTimer.suspend();
       // 取消计时。取消之后,再次开始计时(startCountDown())不会再计时
       //codeTimer.cancel();
      } else {
       jumpBut.setTitle("跳过" + "(\(limitTime)S)", for: .normal);
      }
     }

    示意图

    以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持lingkb。