修改Swift中的用户输入



我正在努力学习Swift,并且已经完成了几个教程,但是,我似乎在兜圈子,需要一些关于如何解决这个问题的指导。

我的目标是创建一个递减计时器,给定用户输入(以秒为单位(,在这种情况下,我选择了一个Stepper来-/+值。然后开始在按下按钮时递减计时器,在这种情况下为"定时器";递减";。计数器显示在标签上。

如果我硬编码起始值,这个问题非常容易,但这对UI测试有什么作用呢。所以,这就是";具有挑战性的";我能够想到的任务是帮助理解SwiftUI是如何工作的。

我遇到的问题是用户传递的变量是不可变的。我尝试过复制它,或者将它分配给其他变量进行操作,但似乎是在兜圈子。朝着正确的方向推动或潜在的解决方案会有很大的帮助。

struct ContentView: View {
@State private var timeInput: Int = 0
var timer = Timer()
var timeInputCopy: Int {
timeInput
}
var body: some View {
Stepper("Input", value: $timeInput, in: 0...150)
Button("Decrement", action: decrementFunction)
Label(String(timeInputCopy), image: "")
.labelStyle(TitleOnlyLabelStyle())
}
func decrementFunction() {
timer.invalidate()
timer = Timer.schedulerTimer(timeInterval: 1, 
target: self, 
selector: #selector(ContentView.timerClass), 
userInfo: nil, 
repeats: true)
}
func timerClass() {
timeInputCopy -= timeInputCopy
if (timeInputCopy == 0) {
timer.invalidate()
}
}
> Cannot assign to property: 'self' is immutable
> Mark method 'mutating' to make 'self' mutable

试图按照Xcode的建议进行自动修复并不能带来有效的解决方案。我觉得我错过了一个核心原则。

正如我在上面的评论中所提到的:

  1. timeInputCopy没有意义——它不是真正的副本,它只是一个返回timeInput的计算属性

  2. 在SwiftUI中使用带有选择器的Timer形式不会有太大的运气。相反,看看Timer发布者。

这里有一个解决方案:

import Combine
import SwiftUI
class TimerManager : ObservableObject {
@Published var timeRemaining = 0

private var cancellable : AnyCancellable?

func startTimer(initial: Int) {
timeRemaining = initial
cancellable = Timer.publish(every: 1, on: .main, in: .common)
.autoconnect()
.sink { _ in
self.timeRemaining -= 1
if self.timeRemaining == 0 {
self.cancellable?.cancel()
}
}
}
}
struct ContentView: View {
@StateObject private var timerManager = TimerManager()
@State private var stepperValue = 60


var body: some View {
Stepper("Input (stepperValue)", value: $stepperValue, in: 0...150)
Button("Start") {
timerManager.startTimer(initial: stepperValue)
}
Label("(timerManager.timeRemaining)", image: "")
.labelStyle(TitleOnlyLabelStyle())
}
}

可以全部在View中完成,但使用ObservableObject可以很好地分离管理定时器的状态和UI的状态。

最新更新