在 D4 的文章,我本來設計了三個物件
目前完成了上面兩個,也讓這個 app 跑起來,不過,我還是想要有個「物件」是這個時鐘的動力來源,試著和真實世界的時鐘一樣有個動力來源。
機芯的英文為 clockwork,接下來就設計 clockwork 物件。
要讓一個物件可以在 Combine 框架下,被別的物件觀察到。在這個框架的設計下,不用讓整個物件被觀察,可以使用 @Published
這個 property wrapper 讓特定 property 開出去讓別的物件 binding。
這個機芯,會有幾個 func 可以讓別人操作
// 機芯
class Clockwork: ObservableObject {
var timer: Cancellable?
var timestamp: TimeInterval = 0
@Published var secondAngle: Double = .zero
@Published var minuteAngle: Double = .zero
@Published var hourAngle: Double = .zero
private var angleUtility: AngleUtility = .init()
private var dateUtility: DateUtility = .init()
init() {
startTimer()
}
func stopTimer() {
timer?.cancel()
}
func startTimer() {
timer = Timer
.publish(every: 0.1, on: .main, in: .common)
.autoconnect()
.sink { [weak self] _ in
self?.updateTime()
}
}
private func updateTime() {
let timestamp = Date().timeIntervalSince1970
calculateAngle(from: timestamp)
self.timestamp = timestamp
}
private func calculateAngle(from timeInterval: TimeInterval) {
secondAngle = angleUtility.getBackwardsSecondHandRadius(from: timeInterval)
minuteAngle = angleUtility.getBackwardsMinuteHandRadius(from: timeInterval)
hourAngle = angleUtility.getBackwardsHourHandRadius(from: timeInterval)
}
private func update(timeInterval: TimeInterval) {
timestamp = timeInterval
print("timestamp updated: \(timestamp)")
}
}
然後,我們來把「機芯」「裝上去」,裝在 View 上。
struct ClockContainerView: View {
var width: CGFloat = 200
var height: CGFloat = 200
@StateObject private var clockwork: Clockwork = .init()
private let angleUtility: AngleUtility = .init()
var body: some View {
ZStack {
ClockDialView()
HandShape(handLength: .hour)
.fill(Color.blue)
.rotationEffect(Angle(degrees: clockwork.hourAngle))
HandShape(handLength: .minute)
.fill(Color.cyan)
.rotationEffect(Angle(degrees: clockwork.minuteAngle))
HandShape(handLength: .second)
.fill(Color.red)
.rotationEffect(Angle(degrees: clockwork.secondAngle))
Circle()
.fill(Color.orange)
.frame(width: 20, height: 20, alignment: .center)
}
.frame(width: width, height: height, alignment: .center)
}
}
Run 起來看一下 clock 長什麼樣子,和原來一樣,所以我們完成了機芯物件的設計,也沒破壞掉專案來可以動的部分。