我正在尝试创建带有倒数计时器的应用。 UI已设置并正确连接到代码。我正在使用一个自定义类来表示类型为DispatchSourceTimer的后台计时器成员的计时器。
我的问题是,本应触发的事件没有触发-关于为什么的任何提示都受到高度赞赏...到目前为止找不到解决方案。
我的目标是通过KVO用剩余时间更新标签,但是到目前为止,由于计时器似乎现在没有被触发,因此KVO当然不会做任何事情。
这是我的View Controller:
import UIKit
class MainViewController: UIViewController {
//MARK: - Properties
var currentTimer = PomTimer()
//MARK: - Outlets
@IBOutlet weak var startStopBtn: UIButton!
@IBOutlet weak var countdownLabel: UILabel!
//MARK: - View Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
countdownLabel.text = currentTimer.description
currentTimer.addObserver(self, forKeyPath: #keyPath(PomTimer.timeLeft), options: .new, context: nil)
}
//MARK: - Button Actions
@IBAction func startStopBtnTapped(_ sender: UIButton) {
if currentTimer.state == .suspended {
currentTimer.resume()
startStopBtn.setImage(UIImage(systemName: "stop.circle.fill"), for: .normal)
} else {
currentTimer.suspend()
startStopBtn.setImage(UIImage(systemName: "play.circle.fill"), for: .normal)
}
}
@IBAction func resetBtnTapped(_ sender: UIButton) {
}
//MARK: - KVO Observer Method
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "timeLeft" {
countdownLabel.text = currentTimer.timeLeft.description
}
}
}
这是我的自定义计时器类:
import Foundation
class PomTimer: NSObject {
//MARK: - Properties
private let uuid = UUID()
private let timerDueTimestamp = Date().addingTimeInterval(25 * 60.0)
@objc var timeLeft: TimeInterval = 25 * 60
//MARK: - Background Timer Logic
lazy var timer: DispatchSourceTimer = {
let t = DispatchSource.makeTimerSource()
t.schedule(deadline: .now() + self.timeLeft, repeating: 1.0)
t.setEventHandler(handler: { [weak self] in
self?.timeLeft -= 1.0
})
return t
}()
enum State {
case suspended, resumed
}
var state: State = .suspended
//MARK: - Custom String
override var description: String {
let f = DateComponentsFormatter()
f.unitsStyle = .positional
f.allowedUnits = [.minute, .second]
f.zeroFormattingBehavior = .pad
return f.string(from: timeLeft)!
}
//MARK: - Functions
func resume() {
if state == .resumed {
return
}
state = .resumed
timer.activate()
}
func suspend() {
if state == .suspended {
return
}
state = .suspended
timer.suspend()
}
//MARK: - Object Lifecycle
deinit {
timer.setEventHandler {}
timer.cancel()
resume()
}
}