xcode 为什么我的SwiftUI .onChange修饰符没有接收@Binding更改?

wmvff8tz  于 2023-06-30  发布在  Swift
关注(0)|答案(1)|浏览(162)

我正在构建一个应用程序,该应用程序从API获取并解码一些数据。返回的一些数据是布尔值,我希望允许用户进行切换(使用Toggle视图)。
一旦切换,我想一个动作被执行(写回服务器)。我以前是通过onChange修饰符来实现的,但后来我的视图层次结构中需要一组更深层次的View对象,这导致我将@Binding属性向下传递到这些视图中。
只要我达到视图深度3onChange就不会被触发。我希望下面的示例代码能充分说明这个问题(我意识到使用的术语不正确,只是一个例子。

import SwiftUI

struct CPU: Hashable {
    let name: String
    var runners: [Runner]
}

struct Runner: Hashable {
    let name: String
    var isRunning: Bool
}

struct RunnersView: View {
    @Binding var runners: [Runner]
    
    var body: some View {
        VStack {
            ForEach($runners, id: \.self) { $runner in
                Toggle(runner.name, isOn: $runner.isRunning)
            }
        }
        .onChange(of: runners) { newValue in
            print("runners changed in RunnersView:")
            print(runners)
        }
    }
}

struct CPUView: View {
    @Binding var cpu: CPU
    
    var body: some View {
        Section(cpu.name) {
            RunnersView(runners: $cpu.runners)
        }
        .onChange(of: cpu) { newValue in
            print("cpu changed in CPUView:")
            print(cpu)
        }
    }
}

struct ContentView: View {
    @State private var cpus = [
        CPU(name: "CPU 1", runners: [
            Runner(name: "Runner 1", isRunning: false),
            Runner(name: "Runner 2", isRunning: false),
            Runner(name: "Runner 3", isRunning: false),
        ]),
        CPU(name: "CPU 2", runners: [
            Runner(name: "Runner 4", isRunning: false),
            Runner(name: "Runner 5", isRunning: false),
            Runner(name: "Runner 6", isRunning: false),
        ]),
    ]

    var body: some View {
        VStack {
            List($cpus, id: \.self) { $cpu in
                CPUView(cpu: $cpu)
            }
        }
        .padding()
        .onChange(of: cpus, perform: { newValue in
            print("cpus changed in ContentView:")
            print(cpus)
        })
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

上面的代码在切换时会触发ContentView中的onChange,但在其他视图中不会。
我试着仔细检查所有@Binding声明是否正确,并将一些声明更改为@State,但不可否认,我对SwiftUI相当陌生。

dauxcl2d

dauxcl2d1#

你的模型结构体需要是Identifiable或者有一个id参数来处理ForEach,例如。

struct Runner: Identifiable {
    let id = UUID()

...

ForEach($runners) { $runner in

有关详细信息,请参阅docs
...集合的元素必须符合Identifiable,或者您需要为ForEach初始化器提供id参数。

相关问题