SwiftUI-YAPPNU(另一个@已发布属性未更新)



在下面的代码中,作为填字游戏应用程序的一部分,我创建了一个Grid,它包含正方形、一个@Published正方形数组和一个GridView,用于显示Grid的实例,Grid。当我在GridView中更改网格的正方形时,GridView会像预期的那样重新创建,我会看到一个"quot;而不是";A";。

现在我又增加了一个级别——谜题包含一个@Published网格,网格。因此,在PuzzleView中,我使用puzzle.griddy。但这不起作用。字母不会改变,PuzzleView身体上的一个断点也不会被击中。

为什么?我正在开发一款应用程序,我真的需要这3种不同的结构。

import SwiftUI

class Square : ObservableObject {
@Published var letter: String

init(letter: String){
self.letter = letter
}
}
class Grid : ObservableObject {
@Published var squares:[[Square]] = [
[Square(letter: "A"), Square(letter: "B"), Square(letter: "C")],
[Square(letter: "D"), Square(letter: "E"), Square(letter: "F"), ]
]

}
class Puzzle: ObservableObject {
@Published var griddy: Grid = Grid()
}
struct GridView: View {
@EnvironmentObject var griddy: Grid

var body: some View {
VStack {
Text("(griddy.squares[0][0].letter)")
Button("Change Numbers"){
griddy.squares[0][0] = Square(letter:"!")
}
}
}
}

struct PuzzleView: View {
@EnvironmentObject var puzzle: Puzzle

var body: some View {
VStack {
Text("(puzzle.griddy.squares[0][0].letter)")
Button("Change Numbers"){
puzzle.griddy.squares[0][0] = Square(letter:"!")
}
}
}
}

struct ContentView_Previews: PreviewProvider {

static var previews: some View {
// PuzzleView().environmentObject(Puzzle())
GridView().environmentObject(Grid())
}
}

从技术上讲,您可以将其添加到Puzzle对象中:

var anyCancellable: AnyCancellable? = nil
init() {
self.anyCancellable = griddy.objectWillChange.sink(receiveValue: {
self.objectWillChange.send()
})
}

这是我在另一篇SO文章中发现的一个技巧,它会导致子对象的更改,从而触发父对象的objectWillChange

编辑:

我想注意的是,如果您更改子对象:

puzzle.griddy = someOtherGriddyObject

则您仍将订阅griddy对象的更改,并且不会收到新的更新。

您可以可能通过在更改对象后更新可取消项来度过难关:

puzzle.griddy = someOtherGriddyObject
puzzle.anyCancellable = puzzle.griddy.objectWillChange.sink(receiveValue: {
puzzle.objectWillChange.send()
})

从这个方向思考:在MVVM SwiftUI概念中,每个引入的ObservableObject实体都必须与相应的视图ObservedObject配对(EnvironmentObjectObservedObject相同,只是注入机制不同(,因此ViewModel中的特定更改将刷新相应的view,没有其他魔术/自动从模型到视图的更改传播。

所以如果SquareObservableObject,那么应该有一些SquareView,作为

struct SquareView {
@ObservedObject var vm: Square
...

因此,如果你的Puzzle可观测包括Grid可观测,那么对应的具有观察到的谜题的PuzzleView应该包括具有观察到网格的GridView,其中应该包括具有观测到的正方形的SqareView

Ie。

struct PuzzleView: View {
@EnvironmentObject var puzzle: Puzzle

var body: some View {
GridView().environmentObject(puzzle.griddy)
}
}
// ... and same for GridView, and so on...

这种方法产生了非常优化的更新,因为修改一个Square只会刷新一个相应的SquareView。

但是,如果在一个容器更新中累积所有平方。objectWillChange,那么修改一个平方会导致整个UI更新,这对UI流畅性和电池都是不利的

因为Grid是引用类型,griddy发生突变时会触发@Published

class Puzzle: ObservableObject {
@Published var griddy: Grid = Grid()
}

注意,griddy实际上并没有发生突变,因为它是一个参考。

但为什么它在@EnvironmentObject var griddy: Grid中有效?

我的猜测是,SDK在@ObservableObject中隐式地观察发布者。

但也许有人能提供更详细的答案。

我个人会避免长的发布链,而只是扁平化嵌套结构。

最新更新