xcode @Bindable未触发对UIViewControllerRepresentable中updateViewController(_:context:)的调用

lawou6xi  于 2023-06-30  发布在  其他
关注(0)|答案(1)|浏览(99)

我目前正在试用新的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,这与我的预期行为非常匹配。但正如所指出的,我认为这是对观察框架的滥用。

42fyovps

42fyovps1#

编辑:@State var dataSource: DataSource是一个解决方案,直到它被修复,因为@State不应该是必要的,它甚至是不正确的使用它没有一个init。
所以你不需要@Bindable,因为在representable中,你不会创建任何SwiftUI视图来传递绑定。然而,我测试了即使只有var dataSource: DataSourceupdateUIViewController时,也没有调用tapCount设置,所以没有配置读取依赖项。我猜他们只是还没有实现它,因为传入整个对象而不仅仅是所需的数据是不常见的,但我相信他们最终会实现的。也许检查它是否在UIViewRepresentable中工作,如果它在那里工作,那么他们可能只是忘记了UIViewControllerRepresentable
仅供参考,与简单类型相比,当视图采用丰富的模型对象时,它们的预览能力较差,因此@Binding var tapCount: Int无论如何都是更好的选择。

相关问题