我正在尝试创建一个视图,一旦用户按下按钮,5 个圆圈(灯)就会一个接一个亮起。但是,当模型更改灯的状态时,视图不会更新以表示每个灯的状态。
struct ReactionLightsView: View {
@ObservedObject var viewModel: ReactionLightsViewModel
var body: some View {
VStack {
VStack(spacing: 0) {
HStack {
ForEach(viewModel.lights) { light in
Circle()
.foregroundColor(light.color)
}
}
} .padding()
Button(action: viewModel.start ) {
Text("Start")
}
}
}
}
class ReactionLightsViewModel: ObservableObject {
@Published private var model: ReactionLightsModel
init(){
model = ReactionLightsModel()
}
var lights: [Light] {
model.lights
}
func start() {
model.startTest()
}
}
struct ReactionLightsModel {
private(set) var lights: [Light] = [Light(), Light(), Light(), Light(), Light()]
private(set) var start: UInt64?
private(set) var stop: UInt64?
private(set) var reactionTimeNanoseconds: UInt64?
mutating func startTest() {
print("start reaction test")
for i in 0..<5 {
lights[i].turnOn();
sleep(1)
}
for i in 0..<5 {
lights[i].turnOff()
}
start = DispatchTime.now().rawValue
print("done with reaction test")
}
mutating func stopTest() {
stop = DispatchTime.now().rawValue
reactionTimeNanoseconds = (stop! - start!)
print(reactionTimeNanoseconds)
}
}
最初,我将灯作为一个布尔数组,通过这个实现,灯会变成红色(打开),但只有在 5 秒过去后才会同时亮起。但是,我并没有将每盏灯更改为它自己的对象,并且视图根本不会更新。
struct Light: Identifiable {
private(set) var isLit: Bool = false
private(set) var color: Color = .gray
let id = UUID()
mutating func turnOn() {
isLit = true
color = .red
}
mutating func turnOff() {
isLit = false
color = .gray
}
}
非常感谢有关如何解决此问题的任何建议以及有关如何改进我的代码的任何其他建议。
答案 0 :(得分:1)
现在,您正试图在主线程上 sleep
- 我怀疑系统甚至不会让您这样做。通常,应该避免使用 sleep
,因为它会停止线程的执行,尤其是不在 UI 线程上。从您的变量名称来看,您似乎正准备测试某人对所有亮起或熄灭的灯的反应时间,这也不适用于 sleep
策略,因为按下任何按钮都会被阻止通过 sleep
策略。我想您仍然可以在sleep
调用之后测量,但是您将失去测量早期发生的任何事情的能力。
如果您删除 sleep
和关闭灯的代码,您会看到灯do实际上被打开了,所以这并不是 UI 不是' t 随数据变化而更新。
我建议您重写代码以使用 Timer
或 DispatchQueue
asyncAfter
。您需要跟踪灯的状态以及接下来应该点亮的灯。
更新,显示 Timer
示例的开头:
struct ReactionLightsModel {
private(set) var lights: [Light] = [Light(), Light(), Light(), Light(), Light()]
private var currentLight = 0
private(set) var start: UInt64?
private(set) var stop: UInt64?
private(set) var reactionTimeNanoseconds: UInt64?
mutating func turnOnNextLight() {
lights[currentLight].turnOn()
currentLight += 1
if currentLight == lights.count {
currentLight = 0
}
}
}
class ReactionLightsViewModel: ObservableObject {
@Published private var model: ReactionLightsModel
var timer : Timer?
init(){
model = ReactionLightsModel()
}
var lights: [Light] {
model.lights
}
func start() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.model.turnOnNextLight()
}
}
}