微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用更改项目数量更新 ForEach 的问题 - .count 似乎返回错误值

如何解决使用更改项目数量更新 ForEach 的问题 - .count 似乎返回错误值

我创建了一个简单的视图,旨在显示存储在 Observable Object 属性中的数组的内容

struct Satellite {
    let name: String
    let orbit: Double
    let color: Color
}

class OrbitalSystem: ObservableObject{
    @Published var objects: [Satellite] =  []
}


struct OrbitalSystemView: View {
    
    @Observedobject var orbitalSystem: OrbitalSystem
    
    var body: some View{

        vstack{
            ForEach(0..<orbitalSystem.objects.count){ n in
                HStack{
                    Text("\(orbitalSystem.objects[n].name)")
                    Spacer()
                    Text("\(orbitalSystem.objects[n].orbit,specifier: "%.2f")")
                }
                .padding()
                .background(orbitalSystem.objects[n].color)
            }.padding()
        }
    }
}

然后我想在 ContentView 中使用这个通用视图,但是在应用程序中,我使用的数据结构(struct Planet)与通用视图(struct Satellite)中使用的结构不同。为了保持所需的更改最少,我向 struct Planet 添加一个计算属性,将 Planet 的内容转换为元素 Satellite。对 ContentView 中的行星数组进行任何更改后,属性观察者会将其转换为卫星数组并将其存储在 Observedobject 属性中。要在初始加载时更新视图,请使用 .onAppear 修饰符设置行星阵列。

struct Planet {
    let name: String
    let distancetoSun: Int
    let surface: Color
    
    var satellite : Satellite {
        Satellite(name: self.name,orbit: Double(self.distancetoSun),color: self.surface)
    }
}


struct ContentView: View {
    @Observedobject var planetarySystem = OrbitalSystem()
    
    @State private var planets: [Planet] = []{
        didSet{
            var objects = [Satellite]()
            for planet in planets {
                objects.append(planet.satellite)
            }
            planetarySystem.objects = objects
        }
    }
    
    var body: some View {
            OrbitalSystemView(orbitalSystem: planetarySystem)
                .onAppear{
                    planets = [
                        Planet(name: "Mercury",distancetoSun: 1,surface: Color.orange),Planet(name: "Venus",distancetoSun: 2,surface: Color.gray),Planet(name: "Earth",distancetoSun: 3,surface: Color.blue),Planet(name: "Mars",distancetoSun: 4,surface: Color.red)
                    ]
                }
    }
}  

这段代码在原理上是有效的,但有一个非常奇怪的行为。我的预期结果是:A Stack of four lines listing: Mercury 1.00,Venus 2.00,Earth 3.00,Mars 4.00 with different colors in the background

但是使用上面的代码,我得到了一个空视图。我通过像这样修改 OrbitalSystem 类得到了预期的结果:

class OrbitalSystem: ObservableObject{
    @Published var objects: [Satellite] =  [
        Satellite(name: "",orbit: 0,color: Color.white),Satellite(name: "",color: Color.white)
    ]
} 

如果

@Published var objects: [Satellite] =  [
            Satellite(name: "",color: Color.white)
            ]

改为这样,结果视图也只显示两行:Mercury 1.00 and Venus 2.00 with the respective background colors

因此,即使数组的内容已更新,ForEach(0..

我使用的是 Xcode 12.3

如果您对此行为做出任何澄清,我将不胜感激。谢谢

解决方法

如果您的数据是动态的(当视图在屏幕上时会发生变化),您需要为每个项目提供一个 ID,以便视图知道何时更新。

方法 1:您可以通过更改 ForEach 循环为其指定本地 ID:

        VStack{
            ForEach(orbitalSystem.objects.indices,id: \.self) { n in
                HStack{
                    Text("\(orbitalSystem.objects[n].name)")
                    Spacer()
                    Text("\(orbitalSystem.objects[n].orbit,specifier: "%.2f")")
                }
                .padding()
                .background(orbitalSystem.objects[n].color)
            }.padding()
        }

方法 2:您可以使 Satellite 符合 Identifiable 并在您 init() 项目时为每个项目提供自己的 ID。在这里,您可以根据需要自定义 ID,并且 ForEach 不需要循环索引,而是循环对象本身。

  1. 使卫星符合可识别性。

    struct Satellite: Identifiable {
        let id = UUID()
        let name: String
        let orbit: Double
        let color: Color
    }
    
  2. 更新每个循环

             VStack{
                 ForEach(orbitalSystem.objects) { object in
                     HStack{
                         Text("\(object.name)")
                         Spacer()
                         Text("\(object.orbit,specifier: "%.2f")")
                     }
                     .padding()
                     .background(object.color)
                 }.padding()
             }
    

如果您查看 ForEach 的不同 init 方法,您会注意到 Range<Int> 方法“在给定的恒定范围内按需计算”视图。因此,您需要对动态数据使用其他初始化之一。

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。