XCode 16 - 对 @Observable 类的一些更改在“升级”到 XCode 16 后不会触发重绘

问题描述 投票:0回答:1

我有一个可以在屏幕上绘制形状的应用程序。用户可以在屏幕上拖动它们。使用 XCode 15 / Swift 5.x 构建时它可以正常工作。但是,当使用 XCode 16 / Swift 6 构建时,对数据模型的更改并不总是会触发重绘。

数据模型包含一个 @Observable 类,其中包含一个“gadgets”数组,每个“gadgets”都是一个结构体,其中包含应绘制的屏幕位置:

@Observable class GadgetModel: Encodable, Identifiable {
    var gadgets  = [GadgetNode]()

每个 GadgetNode 都是一个结构体:

struct GadgetNode : Identifiable, Codable, Hashable {
    public var gadgetType: GadgetType = .unassigned
    public var id: Int = 0             
    var location: CGPoint = CGPoint(x: 50, y: 50)

数据模型中的每个 GadgetNode 都是由一个视图绘制的,用户可以将其拖动到新位置。这是一个高度简化的视图草图:

struct NodeView<Content: View>: View {
    @Environment(GadgetModel.self) private var gadgetModel
    
    @State   var gadget: GadgetNode
    
    @GestureState private var gadgetDragGestureState: CGOffset = .zero
    
    init(gadget: GadgetNode) {
        self.gadget = gadget
    }
    
    var body: some View  {
        ZStack{
            IconBackground(gadget: gadget, drawImage: gadgetModel.redrawGadgets > 0 )
        }   // ZStack
        .frame(width: NodeConstants.nodeWidth, height: NodeConstants.nodeHeight)
        .offset(gadgetDragGestureState)        // Updates view while drgging
        .gesture(gadgetDragGesture)           // sets self.position    }
    
    
    // drag the node
    var gadgetDragGesture: some Gesture {
        DragGesture(minimumDistance: 3)
            .updating($gadgetDragGestureState) {
                (inMotionDragGestureValue, state, _ ) in
                state = inMotionDragGestureValue.translation
            }
             .onEnded { endingDragGestureValue in                    
                let endLocation = gadgetModel.gadgets[gadget.id].location + endingDragGestureValue.translation
                gadget.location = endLocation
                gadgetModel.gadgets[gadget.id].location = endLocation
                 print("drag has ended. GestureDrag = \(gadgetDragGestureState), final position = \(endLocation)")
                 for gadget in gadgetModel.gadgets {
                     print("Gadget \(gadget.id) location = \(gadget.location)")
                 }
            }
    }

这一切似乎仍然正常工作 - 当用户拖动形状时,形状正确地跟随拖动,并且数据模型正确更新。到目前为止,一切都很好。

有一个封闭的视图绘制了所有形状,这就是事情变得奇怪的地方。如果在屏幕上拖动形状,它们就会恢复到原来的位置。但是,如果用户添加新形状,所有形状都会正确绘制在正确的位置(同样,这对于 Xcode 15 来说没问题)。

封闭视图还查看数据模型:

struct GadgetDocumentView: View {
    @Environment(GadgetModel.self) private var gadgetModel

有一个 ViewBuilder 函数返回各种形状,并且每个形状都被绘制到屏幕上:

               ForEach(gadgetModel.gadgets) { gadget in
                    getGadgetView(gadget)       // returns a @Viewbuilder view
                      .zIndex(Double(gadget.id))
                        .position(gadget.location)

我很抱歉还没有创建这个的最小可执行版本 - 我希望比我更好地理解 @Observable 行为和 @ViewBuilder 行为的人会立即认识到这个问题(我大概在做一些愚蠢的事情 - 也许像制作各个形状处理拖动事件,而不是在封闭视图中处理它们?)。

有什么想法吗?

swiftui observable xcode16
1个回答
0
投票

这是一个 SwiftUI 错误 - 过度优化导致数据模型更改被忽略。

我更换了:

                   ForEach(gadgetModel.gadgets) { gadget in
                        getGadgetView(gadget)       // returns a @Viewbuilder view
                          .zIndex(Double(gadget.id))
                          .position(gadget.location)

               ForEach(gadgetModel.gadgets) { gadget in
                    getGadgetView(gadget)       // returns a @Viewbuilder view
                      .zIndex(Double(gadget.id))
                      .position(gadgetModel.gadgets[gadget.id].location)
© www.soinside.com 2019 - 2024. All rights reserved.