SwiftUI ObservableObject 的行为不一致,具体取决于调用站点的来源
Posted
技术标签:
【中文标题】SwiftUI ObservableObject 的行为不一致,具体取决于调用站点的来源【英文标题】:Inconsistent behavior of SwiftUI ObservableObject depending on source of call site 【发布时间】:2021-06-14 14:44:22 【问题描述】:在将数据从 SpriteKit 场景传递到 SwiftUI 视图的持续探索中,我发现了以下谜团(至少对我而言)。我希望解决方案可以打破僵局。 我有一个 ContentView,它使用 SpriteView() 来包含/显示一个名为 GameScene 的 SpriteKit 场景。 我有一个名为 Counter() 的类,它是 ObservableObject 的子类。 (注意 add(count) 函数体中的 print 语句。)
import SwiftUI
class Counter: ObservableObject
@Published var count : Int = 0
func add(count: Int)
self.count += count
print("Add \(count); new total: \(self.count)")
在 ContentView 中,为了测试和比较,我添加了一个按钮,调用 add(count) 函数:
import SwiftUI
import SpriteKit
struct ContentView: View
@ObservedObject var counter = Counter()
var scene: SKScene
let scene = GameScene()
scene.size = CGSize(width: 300, height: 400)
scene.scaleMode = .fill
return scene
var body: some View
VStack
SpriteView(scene: scene)
.frame(width: 300, height: 400)
.ignoresSafeArea()
Button
counter.add(count: 1)
label:
Text("Add to count")
Text("New count = \(counter.count)")
当按钮(在 ContentView 中)被点击时,计数会增加并立即按预期显示。
在 GameScene 中,我对 add(count) 函数的调用几乎相同,但更新 ContentView 失败(拒绝?)。
class GameScene: SKScene
var counter = Counter()
var count = 0
...
//a SpriteKitNode called "button" is created then added in didMove(toView)//
...
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
guard let touch = touches.first else return
let location = touch.location(in: self)
if button.contains(location)
counter.add(count: 1)
无论调用来自 GameScene 还是 ContentView,print 语句的内容都是相同的。第一次点击任一按钮时,它会显示:
加1;新总数:1
加1;新总数:2
加1;新总数: 3 ,依此类推。
换句话说,在调用用于更新已发布变量的 func 之前,它们似乎表现相同。但是……
谜团:
为什么来自 ContentView 的调用会触发所需的更新,而来自 GameScene 的相同调用却不会?
我期待着从我疲惫的眼睛中去除鳞片!
【问题讨论】:
【参考方案1】:在您的GameScene
中,当您声明属性时,您正在创建一个全新的Counter
实例:
var counter = Counter()
相反,您应该将ContentView
拥有的Counter
实例传递给GameScene
,以便它们对同一个对象进行变异。
您可以为GameScene
创建一个初始化程序以将Counter
作为参数,或者您可以执行以下操作:
//in GameScene:
var counter : Counter?
//in GameScene when the button is pressed:
counter?.add(count: 1)
//in ContentView:
let scene = GameScene()
scene.counter = counter
【讨论】:
我遵循了@jnpdx 的建议,它还需要将 GameScene 中的调用更改为 counter?.add(count: 1),现在它可以工作了。我怀疑问题出在实例的重新创建上,并尝试使用 var counter: Counter?但我错过了 ContentView 中对场景的更改。非常感谢您花时间提供帮助!以上是关于SwiftUI ObservableObject 的行为不一致,具体取决于调用站点的来源的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI/组合监听 ObservableObject 中的多个发布者
SwiftUI = ObservableObject 作为类的选择
SwiftUI 致命错误:未找到“”类型的 ObservableObject
在 SwiftUI 中将 ObservableObject 链接到 DatePicker