SwiftUI 视图不基于@ObservedObject 更新

Ant*_*ton 20 arrays ios swiftui observableobject

在下面的代码中,观察到的对象被更新,但观察它的视图没有更新。知道为什么吗?

代码在屏幕上显示 10 个数字 (0..<10) 和一个按钮。每当按下按钮时,它会随机选择 10 个数字之一并翻转其可见性(可见?隐藏,反之亦然)。

打印语句显示按钮正在更新数字,但视图不会相应更新。我知道更新数组中的值不会改变数组值本身,所以我使用手册objectWillChange.send()调用。我原以为应该触发更新,但屏幕永远不会改变。

任何的想法?我对NumberLine用作类或结构的解决方案感兴趣,或者根本不使用NumberLine类型,而只是在ContentView结构中使用数组变量。

截屏

这是代码:

import SwiftUI

struct ContentView: View {

    @ObservedObject var numberLine = NumberLine()

    var body: some View {
        VStack {
            HStack {
                ForEach(0 ..< numberLine.visible.count) { number in
                    if self.numberLine.visible[number] {
                        Text(String(number)).font(.title).padding(5)
                    }
                }
            }.padding()

            Button(action: {
                let index = Int.random(in: 0 ..< self.numberLine.visible.count)
                self.numberLine.objectWillChange.send()
                self.numberLine.visible[index].toggle()
                print("\(index) now \(self.numberLine.visible[index] ? "shown" : "hidden")")
            }) {
                Text("Change")
            }.padding()
        }
    }
}

class NumberLine: ObservableObject {
    var visible: [Bool] = Array(repeatElement(true, count: 10))
}
Run Code Online (Sandbox Code Playgroud)

Sau*_*jaj 26

我遇到了同样的问题。对我来说,用@StateObject替换@ObservedObject是有效的。

  • 我发现这个问题面临着关于异步更改不更新 ObservedObject 的类似问题,实际上这个更改也解决了我的问题。不知道为什么,但如果有人遇到此线程,请务必尝试一下。 (8认同)
  • 这个解决问题的改变与这里的问题没有关系。 (2认同)

Asp*_*eri 24

随着@ObservedObject一切都很好...让我们分析...

迭代 1:

无需更改代码,只添加以下行(显示为文本当前visible数组状态)

VStack { // << right below this
    Text("\(numberLine.visible.reduce(into: "") { $0 += $1 ? "Y" : "N"} )")
Run Code Online (Sandbox Code Playgroud)

并运行,您会看到它Text已更新,因此可观察对象可以正常工作

演示

迭代 2:

删除self.numberLine.objectWillChange.send()并使用@Published视图模型中的默认模式

class NumberLinex: ObservableObject {
    @Published var visible: [Bool] = Array(repeatElement(true, count: 10))
}
Run Code Online (Sandbox Code Playgroud)

运行,您会看到更新的工作方式与上面的第一个演示相同。

*但是......主要数字ForEach仍然没有更新......是的,因为问题ForEach- 你使用构造函数Range生成常量视图的组设计(记录!)。

!! 这就是原因 - 您需要 dynamic ForEach,但需要更改该模型。

迭代 3 - 最终:

动态ForEach构造函数要求迭代数据元素是可识别的,因此我们需要结构作为模型和更新的视图模型。

这是最终解决方案和演示(使用 Xcode 11.4 / iOS 13.4 测试)

演示2

VStack { // << right below this
    Text("\(numberLine.visible.reduce(into: "") { $0 += $1 ? "Y" : "N"} )")
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你!!我非常感谢:1)Anton 花时间发布这段代码,2)@Asperi 了解答案并花时间写出来,3)StackOverflow 创建了一个平台,其中两个你们可以找到彼此,4) Google 奇迹般地将我相当模糊的查询转换为我需要的_exact_ StackOverflow 链接。我花了 2 分钟来调试一个我担心需要几个小时的东西。谁知道 `ForEach` 的这种行为!? (2认同)

Ant*_*ton 5

@Asperi,根据您的见解,问题出在功能上ForEach而不是功能上@ObservableObject,这里对原始版本进行了一个小修改,以实现这一点:

import SwiftUI

struct ContentView: View {

    @ObservedObject var numberLine = NumberLine()

    var body: some View {
        VStack {
            HStack {
                ForEach(Array(0..<10).filter {numberLine.visible[$0]}, id: \.self) { number in
                    Text(String(number)).font(.title).padding(5)
                }
            }.padding()

            Button(action: {
                let index = Int.random(in: 0 ..< self.numberLine.visible.count)
                self.numberLine.visible[index].toggle()
            }) {
                Text("Change")
            }.padding()
        }
    }
}

class NumberLine: ObservableObject {
    @Published var visible: [Bool] = Array(repeatElement(true, count: 10))
}
Run Code Online (Sandbox Code Playgroud)