背景

最近项目中,需求做一个如图所示的倒计时控件,上网搜了一圈,发现大家的办法迥然不同,都是把倒计时的秒,转化成时分秒然后拼接字符串,见下图

iOS 电商倒计时

网上大部分采用的办法 /post/684490…

iOS 电商倒计时

在我的项目中,期望这个倒计时控件的format是能够自定义的,所以核算时分秒这样的方法,对于我的需求是不太灵敏的

已然format需求自定义,那么很容易想到一个时刻格局处理的类:DateFormatter

思路

后端返回的字段

init_time // 需求倒计时的时长,单位ms
format // 展示的倒计时格局

我们的需求其实十分清晰,便是完成一个能够自定义format的倒计时label

那我们拆解一下整个需求:

  • 自定formatlabel
    • Date自定义format显现
    • 指定Date自定义format显现
  • 能够进行倒计时功用

那么我们怎样才能把要倒计时的时长,转化为时分秒呢?

  • 直接核算后端给的init_time,算出是多少小时,多少分钟,多少秒
  • 假如我从每天的零点开端计时,然后把init_time作为偏移量不便是我要倒计时的时刻吗,并且这个能够完美处理需求自定义format的问题,Date能够直接经过 DateFormatter转化成字符串
    iOS 电商倒计时

Date自定义format显现

let df = DateFormatter()
df.dateFormat = "hh:mm:ss"
print("", df.string(from: Date()), "\n\n")
输出: 03:56:28 

指定Date自定义format显现

let df = DateFormatter()
var calendar = Calendar(identifier: .gregorian)
let startOfDate = calendar.startOfDay(for: Date())
df.dateFormat = "hh:mm:ss"
print("", df.string(from: startOfDate), "\n\n")
输出: 12:00:00 

完整功用

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    initCountdownTimer()
    return true
  }
  private var timer: DispatchSourceTimer?
  private var second = 0
  // 单位ms
  var delayTime = 0
  // 单位ms
  var interval = 1000
  var initSecound = 10
  var format = "hh:mm:ss"
  private lazy var startDate: Date = {
        var calendar = Calendar(identifier: .gregorian)
    let startOfDate = calendar.startOfDay(for: Date())
    return Date(timeInterval: TimeInterval(initSecound), since: startOfDate)
 }()
 private lazy var df: DateFormatter = {
        let df = DateFormatter()
    df.dateFormat = format
    return df
 }()
 func initCountdownTimer() {
    timer = DispatchSource.makeTimerSource(queue: .main)
    timer?.schedule(deadline: .now() + .milliseconds(delayTime), repeating: .milliseconds(interval), leeway: .milliseconds(1))
    timer?.setEventHandler { [weak self] in
      self?.updateText()
      self?.second += 1
    }
    timer?.resume()
  }
  func deinitTimer() {
    timer?.cancel()
    timer = nil
  }
  func updateText() {
    if second == initSecound && second != 0 {
      deinitTimer()
    }
    if second == initSecound {
      return
    }
    let date = Date(timeInterval: -TimeInterval(second + 1), since: startDate)
    let text = df.string(from: date)
    print(text)
  }
    输出:
    12:00:09
    12:00:08
    12:00:07
    12:00:06
    12:00:05
    12:00:04
    12:00:03
    12:00:02
    12:00:01
    12:00:00

以上整个功用基本完成,但是仔细的同学必定发现了,按道理小时部分应该是00,但是实践是12,这是为什么呢,为什么呢?

我在这里研讨了好久,上网查了许多材料

最后去研讨了foramt每个字母的意思才知道:

  • h 代表 12小时制

  • H 代表 24小时制,假如想要显现00,把”hh:mm:ss”改成”HH:mm:ss”即可

时刻格局符号字段详见