我有一个SwiftUI视图,用于显示和更新源自@ObservedObject的数据。下面的代码示例按预期方式工作,除非@ObservedObject恰好是UIViewController的子类。在这种情况下,将对@ObservedObject进行数据更新,但它们不会触发View内容的重新加载。
这是SwiftUI视图:
struct ContentView : View {
@ObservedObject var scene: SceneViewController
var body: some View {
VStack {
Text("The time is: \(scene.currentSimTimestamp.description(with: .current))")
Button(action: {self.scene.currentSimTimestamp = Date()},
label: {Text("Update")})
}
}
}
这是@ObservedObject:
class SceneViewController: UIViewController, ObservableObject {
@Published var currentSimTimestamp: Date = Date()
}
按下“更新”按钮将导致Scene.currentSimTimestamp中存储的值更新,但是ContentView不会重新加载(屏幕不会更新以反映数据更改)。
将class SceneViewController: UIViewController, ObservableObject {
更改为class SceneViewController: ObservableObject {
将导致更新按预期显示。
这似乎是一个错误,因为我看过的Apple文档和视频似乎暗示任何Class都可以采用ObservableObject,并且确实没有编译器问题产生。但是我想念什么吗?
(下面添加了示例SceneDelegate代码以将示例代码重现到项目中)
import UIKit
import SwiftUI
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
let sceneController: SceneViewController = SceneViewController()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView(scene: sceneController)
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
...
答案 0 :(得分:1)
另外两种获取通知的方式:
最简单的方法就是调用发布者(AFAIK scene.currentSimTimestamp
不必是@Published
):
Button(action: {
self.scene.currentSimTimestamp = Date()
self.scene.objectWillChange.send()
},
label: {Text("Update")})
稍微复杂一些,但恕我直言,合并方式稍微更清洁: https://stackoverflow.com/a/60126962/301790
答案 1 :(得分:0)
作为一种解决方法,我发现我可以从View Controller中拉出@Published属性包装器,并将其移动到新的(非UIViewController)ObservableObject类中,该类仅用于发布此属性。仅有此更改,它才能按预期运行。显然,解决方法很麻烦,但是它确实允许现有UIViewController拥有的数据在SwiftUI视图中按预期使用。这是更新:
class NewClass: ObservableObject {
@Published var timestamp: Date = Date()
}
class SceneViewController: UIViewController {
var currentSimTimestamp: NewClass()
override func viewDidLoad() {
super.viewDidLoad()
// Shown here with our SwiftUI view as a child in our ViewController's hierarchy
let contentView = ContentView(newClass: currentSimTimestamp)
let contentViewController = UIHostingController(rootView: contentView)
addChild(contentViewController)
view.addSubview(contentViewController.view)
...
}
}
struct ContentView : View {
@ObservedObject var newClass: NewClass
var body: some View {
VStack {
Text("The time is: \(newClass.timestamp.description(with: .current))")
Button(action: {self.newClass.timestamp = Date()},
label: {Text("Update")})
}
}
}