SwiftUI之Timer的封装

前言

如果我们需要定期运行一些代码,也许我们只为的做一下倒计时之类的,我们最好使用Timer和onReceive()修饰符。项目中可能会多出使用倒计时,为此自己封装了一个。

【点击查看源代码】Bepayun / SwiftUI-Timer

功能

效果图:


timer.gif

调用方法

SendVerificationCode(width: 90, height: 48, topLeft: true, action: {
  // 操作信息
  // 测试代码
  NotificationCenter.default.post(name: .sendSuccess, object: nil, userInfo: ["success": true])
  return true
 })

实现原理

定时器运作根据状态机来判断什么时候该进行怎样的工作

enum TimerState: Int {
  case send = 0 // 初始状态 发送
  case waiting = 1 // 等待确认发送
  case timer = 2 // 开始倒计时
}

定时器的默认状态设置为.send

@State var timerState: TimerState = .send

创建计时器发布者的代码及相关实例如下所示:

// 给定时器添加半秒的容忍度
let timer = Timer.publish(every: 1, on: .main, in: .common)  // .autoconnect()
@State var timerIns: AnyCancellable?
@State var countDown: Int = SendVerificationCode.DURATION // 倒计时
@State var startTime: Double = NSDate().timeIntervalSince1970

timerIns类型擦除可取消对象,在取消时执行提供的闭包。订阅者实现可以使用这种类型来提供一个“取消令牌”,使调用者可以取消发布者,但不能使用“订阅”对象来请求项目。一个 AnyCancellable 实例在取消初始化时会自动调用 Cancellable/cancel()
使用给定的取消时间闭包初始化可取消对象。 参数取消:cancel() 方法执行的闭包。如:

timerIns?.cancel()

定时器触发时,要判断是否成功:定时器触发失败,定时器的状态置为.send状态;定时器触发成功要先记录当前时间,定时器状态置为.timer,再启动定时器。

.onReceive(NotificationCenter.default.publisher(for: .sendSuccess)) { obj in
   if (obj.userInfo?["success"] as? Bool ?? false)  {
       // 记录当前时间
       startTime = NSDate().timeIntervalSince1970
       // 验证码发送成功
       timerState = .timer
       // 启动timer
       connectTimer()
   } else {
       // 验证码发送失败
       timerState = .send
  }
 }                    

这里我们还要判断程序的状态:程序进入前台我们需要重启定时器;程序进入后台我们得暂停定时器。

.onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
   // 程序进入前台
  // 重启计时器
  connectTimer()
 }
.onReceive(NotificationCenter.default.publisher(for: UIApplication.didEnterBackgroundNotification)) { _ in
  // 程序进入后台暂停计时器
  stopTimer()
}

你可能感兴趣的:(SwiftUI之Timer的封装)