How Does Update Closure Work in RealityView

I have looked here: Reality View Documentation

Found this thread: RealityView Update Closure Thread

I am not able to find documentation on how the update closure works.

I am loading attachments using reality view's attachment feature (really helpful). I want to remove them programmatically from another file. I found that @State variables can be used. But I am not able to modify them from out side of the ImmersiveView swift file. The second problem I faced was even if I update them inside the file. My debugging statements don't execute.

So exactly when does update function run. I know it get's executed at the start (twice for some reason). It also get's executed when I add a window using:

openWindow?(id: "ButtonView")

I need to use the update closure because I am also not able to get the reference to RealityViewAttachment outside the RealityView struct.

My Code(only shown the code necessary. there is other code):

@State private var pleaseRefresh = ""
@StateObject var model = HandTrackingViewModel()

var body: some View {
        RealityView { content, attachments in
            if let immersiveContentEntity = try? await Entity(named: "Immersive", in: realityKitContentBundle) {
                content.add(immersiveContentEntity)
            }
            
            content.add(model.setupContentEntity())
            content.add(entityDummy)
            
            print("View Loaded")
        } update: { content, attachments in
            print("Update Closure Executed")
            if (model.editWindowAdded) {
                print("WINDOW ADDED")
                let theattachment = attachments.entity(for: "sample")!
                entityDummy.addChild(theattachment)
                // more code here
            }
            
        }
    attachments: {
        Attachment(id: "sample") {
            Button(action: {
                model.canEditPos = true
                model.canRotate = false
                pleaseRefresh = "changed"
            }) {
                HStack {
                    Image(systemName: "pencil.and.outline")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 32, height: 32) 
                    Text("Edit Placement")
                        .font(.caption)
                }
                .padding(4) 
            }
            .frame(width: 160, height: 60)
        }
        }

How can the update method (or the code inside it) run when I want it to? I am new to swift. I apologize if my question seems naive.

Answered by Vision Pro Engineer in 795801022

The update closure is called as the RealityView's state changes. Build spatial experiences with RealityKit is a good introduction to RealityKit and Work with Reality Composer Pro content in Xcode has a good overview of attachments.

Removing an attachment from another view is possible. You're off to a good start. Using a boolean (in this case editWindowAdded) to indicate when to display the edit window is the right approach. You just need to change where you use that boolean. In the case of attachments you should only create the attachments if you intend to use it. Here's how I would change your snippet to do that.

struct ImmersiveView: View {
    @State var model:HandTrackingViewModel
    
    var body: some View {
        RealityView { content, attachments in
            print("View Loaded")
        } update: { content, attachments in
            print("Update Closure Executed")
            
            // Add the attachment if it exists
            if let attachment = attachments.entity(for: "sample") {
                // Move the attachment further in front of the camera
                attachment.position = [0, 0, -1.0]
                content.add(attachment)
            }
            
        }
        attachments: {
            // Only create the attachment when the model says to
            if model.editWindowAdded {
                Attachment(id: "sample") {
                    Button(action: {
                    }) {
                        HStack {
                            // ...
                            Text("Edit Placement")
                                .font(.caption)
                        }
                        .padding(4)
                    }
                    .glassBackgroundEffect()
                }
            }
        }
    }
}

Lastly, make sure your model is observable.

@Observable
class HandTrackingViewModel {
    var editWindowAdded = false
}
Accepted Answer

The update closure is called as the RealityView's state changes. Build spatial experiences with RealityKit is a good introduction to RealityKit and Work with Reality Composer Pro content in Xcode has a good overview of attachments.

Removing an attachment from another view is possible. You're off to a good start. Using a boolean (in this case editWindowAdded) to indicate when to display the edit window is the right approach. You just need to change where you use that boolean. In the case of attachments you should only create the attachments if you intend to use it. Here's how I would change your snippet to do that.

struct ImmersiveView: View {
    @State var model:HandTrackingViewModel
    
    var body: some View {
        RealityView { content, attachments in
            print("View Loaded")
        } update: { content, attachments in
            print("Update Closure Executed")
            
            // Add the attachment if it exists
            if let attachment = attachments.entity(for: "sample") {
                // Move the attachment further in front of the camera
                attachment.position = [0, 0, -1.0]
                content.add(attachment)
            }
            
        }
        attachments: {
            // Only create the attachment when the model says to
            if model.editWindowAdded {
                Attachment(id: "sample") {
                    Button(action: {
                    }) {
                        HStack {
                            // ...
                            Text("Edit Placement")
                                .font(.caption)
                        }
                        .padding(4)
                    }
                    .glassBackgroundEffect()
                }
            }
        }
    }
}

Lastly, make sure your model is observable.

@Observable
class HandTrackingViewModel {
    var editWindowAdded = false
}
How Does Update Closure Work in RealityView
 
 
Q