【问题标题】:SwiftUI Published variable doesn't trigger UI updateSwiftUI Published 变量不会触发 UI 更新
【发布时间】:2020-10-18 09:47:08
【问题描述】:

我有一个应用程序,其导航视图列表在以后在应用程序中添加新元素时不会更新。初始屏幕很好,无论我如何编写它们,此时都会触发所有内容,但除此之外,它保持不变。在某些时候,我将我的“init”方法作为 .onappear,动态元素不会进入,但是当我在应用程序中来回移动时,静态元素会被添加多次,这不再是不过我现在的代码。

这是我的内容视图的样子,我尝试将导航视图部分移动到具有已发布 var 的类,以防万一它有帮助,在视觉上它会改变任何东西,也有帮助。

struct ContentView: View {
    
    @ObservedObject var diceViewList = DiceViewList()
    
    var body: some View {
        VStack{
            Text("Diceimator").padding()
            diceViewList.body 
            Text("Luck Selector")
        }
    }
}

和 DiceViewList 类

import Foundation
import SwiftUI
class DiceViewList: ObservableObject {
    @Published var list = [DiceView]()

    init() {
        list.append(DiceView(objectID: "Generic", name: "Generic dice set"))
        list.append(DiceView(objectID: "Add", name: "Add a new dice set"))
        // This insert is a simulation of what add() does with the same exact values. it does get added properly
        let pos = 1
        let id = 1
        self.list.insert(DiceView(objectID: String(id), dice: Dice(name: String("Dice"), face: 1, amount: 1), name: "Dice"), at: pos)
    }

 var body: some View {
        NavigationView {

            List {
                ForEach(self.list) { dView in
                    NavigationLink(destination: DiceView(objectID: dView.id, dice: dView.dice, name: dView.name)) {
                        HStack {  Text(dView.name) }
                    }
                }
            }
        }
    }
    
    func add(dice: Dice) {
        let pos = list.count - 1
        let id = list.count - 1
        self.list.insert(DiceView(objectID: String(id), dice: dice, name: dice.name), at: pos)
        
    }
}

我正在开发最新的 Xcode 11,以防万一

编辑:根据建议编辑代码,问题根本没有改变

struct ContentView: View {
    
    @ObservedObject var vm: DiceViewList = DiceViewList()
    
    var body: some View {


            NavigationView {
                List(vm.customlist) { dice in
                    NavigationLink(destination: DiceView(dice: dice)) {
                        Text(dice.name)
                    }
                } 


        }
    }
}

DiceViewList

class DiceViewList: ObservableObject {
    
    @Published var customlist: [Dice] = []
    func add(dice: Dice) {
 
        self.customlist.append(dice)

    }
     
    init() {
        customlist.append(Dice(objectID: "0", name: "Generic", face: 1, amount: 1))
        customlist.append(Dice(objectID: "999", name: "AddDice", face: 1, amount: 1))
    }
}

【问题讨论】:

  • 您对如何使用 SwiftUI 有一个根本性的误解。简而言之,您的代码应该将视图表示与驱动它的数据分开。换句话说,更新创建DiceViews 列表所需的对象数组,而不是更新DiceViews 数组

标签: ios swift xcode swiftui observableobject


【解决方案1】:

SwiftUI 是从构建 UIKit 应用程序的范式转变。

这个想法是将“驱动”视图(即视图模型)的数据与视图表示关注点分开。

换句话说,如果您有一个显示ChildView(foo:Foo) 列表的ParentView,那么ParentView 的视图模型应该是Foo 对象的数组——而不是ChildViews:

struct Foo { var v: String }

class ParentVM: ObservableObject {
   @Published let foos = [Foo("one"), Foo("two"), Foo("three")]
}

struct ParentView: View {
   @ObservedObject var vm = ParentVM()

   var body: some View {
       List(vm.foos, id: \.self) { foo in 
          ChildView(foo: foo)
       }
   }
}

struct ChildView: View {
   var foo: Foo
   var body = Text("\(foo.v)")
}

因此,在您的情况下,将添加 Dice 对象的逻辑与 DiceViewList 分开(为简洁起见,我冒昧地使用您的特定逻辑):

class DiceListVM: ObservableObject {
   @Published var dice: [Dice] = []

   func add(dice: Dice) {
      dice.append(dice)
   }
}

struct DiceViewList: View {

   @ObservedObject var vm: DiceListVM = DiceListVM()

   var body: some View {
       NavigationView {
          List(vm.dice) { dice in
             NavigationLink(destination: DiceView(for: dice)) {
                Text(dice.name)
             }
       }
   }
}

如果您需要的数据多于 Dice 中的可用数据,只需创建一个包含所有其他属性的 DiceVM,例如 .name.diceobjectId

但要点是:不要存储和出售视图。 - 只处理数据。

【讨论】:

  • 根据您的建议编辑了代码,但它并没有改变任何东西,仍然无法正常工作,也许我在某个地方搞砸了,但看起来和您的很相似
  • “不工作”是什么意思?乍一看,您的代码看起来是正确的,但我不在电脑旁,所以现在无法检查。您是否也可以将您的问题的编辑恢复为原始问题并将您更新的代码添加为附录,否则我的回答对下一个人没有意义@Pierrick584
  • 不工作意味着应用程序启动,但唯一显示的两个列表元素是 init 中的元素,我有一些打印显示列表确实按预期增加,但 UI 从未得到更新
  • @Pierrick584 - 我试过你的代码,它对我有用。您在哪里/如何添加附加项目?例如,如果您在ContentView 中添加了这样的按钮:Button("Add") { self.vm.add(dice: Dice(...)) },这会起作用吗? (对我有用)。如果您在 DiceViewList.init 内有类似 DispatchQueue.main.asyncAfter(deadline: .now() + 2) { self.add(dice: Dice(...)) } 的内容,则相同
  • 是的,虽然是一个和你写的一模一样的按钮。不过,我已经做了一个测试,我在主页上制作了那个确切的按钮,它可以工作。但如果它在子视图中,它不会,即使使用 DispatchQueue.main.async
【解决方案2】:

在测试东西时,我意识到了问题所在。我假设在每个其他类中声明 @ObservedObject var vm: DiceViewList = DiceViewList() 并且需要它的结构会使它们找到相同的对象,但事实并非如此!我尝试将观察到的对象作为参数传递给包含“添加”按钮的子视图,它现在可以按预期工作。

【讨论】:

    猜你喜欢
    • 2021-09-07
    • 1970-01-01
    • 2020-04-30
    • 2021-12-27
    • 1970-01-01
    • 2021-04-01
    • 1970-01-01
    • 2021-10-14
    • 2020-07-10
    相关资源
    最近更新 更多