我目前正在试用新的Observation宏beta,用于SwiftUI状态观察。我的数据模型是一个类,前缀是@Observable:
import Observation
import SwiftUI
import UIKit
@Observable
class DataSource {
var tapCount = 0
init(tapCount: Int = 0) {
self.tapCount = tapCount
}
}
// The wrapper that creates and embeds the UIViewController
struct VCR: UIViewControllerRepresentable {
@Bindable var dataSource: DataSource
func makeUIViewController(context: Context) -> VC {
VC()
}
func updateUIViewController(_ uiViewController: VC, context: Context) {
// Any updates, we want to send to our UIViewController, do them here
print(#function)
uiViewController.lbl.text = String(dataSource.tapCount)
}
}
// The SwiftUI View
struct ContentView: View {
@State private var dataSource = DataSource()
var body: some View {
VStack {
VCR(dataSource: dataSource)
Text("Tap Count: \(dataSource.tapCount)")
Button("Increment from SwiftUI") {
dataSource.tapCount += 1
}
}
}
}
我的SwiftUI视图拥有DataSource属性,它这样声明:@State dataSource = DataSource()
在符合UIViewControllerRepresentable
的结构体中,我将相应的Bindable
声明为DataSource属性:@Bindable dataSource: DataSource
当SwiftUI View将使用符合UIViewControllerRepresentable
的类型时,它会初始化该类型,并将SwiftUI View拥有和创建的@State dataSource
属性作为参数传递给@Bindable dataSource
属性。
问题是,SwiftUI View更新tapCount
属性时,不会触发UIViewControllerRepresentable
中的updateViewController(_:context:)
。
如果我在UIViewControllerRepresentable
中存储tapCount: Int
的属性,并在SwiftUI View中初始化UIViewControllerRepresentable
时将dataSource.tapCount
作为参数传入,那么当dataSource.tapCount
更改时,将触发updateViewController(_:context:)
。
但是我不想传入一个属性,并将其存储在UIViewControllerRepresentable示例中(并且不再读取或写入它),以便Observation API在dataSource中的属性更新时触发update方法。
它应该是这样工作的吗?或者它可能是一个bug?我不确定,我确实向苹果提交了一份反馈报告。这样设置它似乎是不可行的,或者观察API应该起作用的方式。
我知道,根据Apple关于新的Observation宏API的文档,只有实际上 read 的属性才会导致状态更改。我的属性在SwiftUI视图中读取,SwiftUI视图拥有它,并且如上所述,它通过@Bindable绑定到它。
更重要的是,如果我从SwiftUI dataSource属性(拥有并创建dataSource)中删除@State前缀,而是在UIViewControllerRepresentable中为dataSource属性添加@State前缀,那么一切都可以正常工作。* 但这似乎是对Observation宏API的滥用 *。
使用旧的(合并)ObservableObject,@Published和@Observable模式可以按预期工作。但是migration to the Observation macro API, as per the Apple documentation打破了这一点。
对问题的根本原因有什么想法吗?
Xcode版本:15.0 beta(15 A5160 n),iOS 17.0,可观察宏,Beta
非常感谢
[Edit,2023-06-29,12:03]我用UIViewRepresentable
测试了它(没有@Bindable,因为不需要它),然而,同样的问题仍然存在。将Representable中的属性前缀为@State
,这与我的预期行为非常匹配。但正如所指出的,我认为这是对观察框架的滥用。
1条答案
按热度按时间42fyovps1#
编辑:
@State var dataSource: DataSource
是一个解决方案,直到它被修复,因为@State
不应该是必要的,它甚至是不正确的使用它没有一个init。所以你不需要
@Bindable
,因为在representable中,你不会创建任何SwiftUI视图来传递绑定。然而,我测试了即使只有var dataSource: DataSource
和updateUIViewController
时,也没有调用tapCount
设置,所以没有配置读取依赖项。我猜他们只是还没有实现它,因为传入整个对象而不仅仅是所需的数据是不常见的,但我相信他们最终会实现的。也许检查它是否在UIViewRepresentable
中工作,如果它在那里工作,那么他们可能只是忘记了UIViewControllerRepresentable
。仅供参考,与简单类型相比,当视图采用丰富的模型对象时,它们的预览能力较差,因此
@Binding var tapCount: Int
无论如何都是更好的选择。