SwiftUI ObservableObject 的不一致行为取决于调用站点的来源
Inconsistent behavior of SwiftUI ObservableObject depending on source of call site
在将数据从 SpriteKit 场景传递到 SwiftUI 视图的持续探索中,我发现了以下谜团(至少对我而言)。我希望解决方案可以打破僵局。
我有一个 ContentView,它使用 SpriteView() contain/display 一个名为 GameScene 的 SpriteKit 场景。
我有一个名为 Counter() 的 class,它被子class 编辑为一个 ObservableObject。 (注意 add(count) 函数主体中的打印语句。)
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,打印语句的内容都是一样的。第一次点击任一按钮时,它会显示:
加1;新总数:1
加1;新总数:2
加1;新总数: 3 ,依此类推。
换句话说,在调用旨在更新发布的 var 的 func 之前,它们似乎 表现相同。但是...
谜团:
为什么来自 ContentView 的调用触发了所需的更新,而来自 GameScene 的相同调用却没有?
我期待从疲倦的眼睛上取下鳞片!
在您的 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
在将数据从 SpriteKit 场景传递到 SwiftUI 视图的持续探索中,我发现了以下谜团(至少对我而言)。我希望解决方案可以打破僵局。 我有一个 ContentView,它使用 SpriteView() contain/display 一个名为 GameScene 的 SpriteKit 场景。 我有一个名为 Counter() 的 class,它被子class 编辑为一个 ObservableObject。 (注意 add(count) 函数主体中的打印语句。)
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,打印语句的内容都是一样的。第一次点击任一按钮时,它会显示:
加1;新总数:1
加1;新总数:2
加1;新总数: 3 ,依此类推。
换句话说,在调用旨在更新发布的 var 的 func 之前,它们似乎 表现相同。但是...
谜团:
为什么来自 ContentView 的调用触发了所需的更新,而来自 GameScene 的相同调用却没有?
我期待从疲倦的眼睛上取下鳞片!
在您的 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