RealityView content.add Called Twice Automatically

I’m working with RealityView in visionOS and noticed that the content closure seems to run twice, causing content.add to be called twice automatically. This results in duplicate entities being added to the scene unless I manually check for duplicates. How can I fix that? Thanks.

Answered by radicalappdev in 853085022

I made a standalone project based on your code check this out. The good news that the entity is not being duplicated. Let's look at the cod first.

struct ImmersiveView: View {

    @State var launchEntity = Entity()

    var body: some View {
        RealityView { content in

            print("RealityView Content Loaded!") // Called Once
            launchEntity = createLaunchEntity()
            content.add(launchEntity)
        }
    }

    func createLaunchEntity() -> Entity {
        //...
        let entity: Entity = Entity()
        entity.name = "Launch Entity"

        let launchviewComponent = ViewAttachmentComponent(
            rootView: LaunchView()
        )
        entity.components.set(launchviewComponent)

        print("createLaunchEntity was called") // Called Once
        return entity
    }
}

struct LaunchView: View {

    var body: some View {
        VStack {

            Text("Launch View")

        }
        .padding()
        .onAppear() {
            print("Launch view appears!") // Called Twice
        }
    }
}

When I load this immersive space I see 4 lines in the console

RealityView Content Loaded!
createLaunchEntity was called
Launch view appears!
Launch view appears!

What happened

  • RealityView content was called once
  • createLaunchEntity
  • The onAppear closure in the LaunchView was called twice.

That made me wonder if ViewAttachmentComponent is calling LaunchView more than once and yes, that appears to be the case.

When I create the attachment using the attachments closure on RealityView, onAppear is only called once.

    var body: some View {
        RealityView { content, attachments in

            print("RealityView Content Loaded!") // Called Once

            content.add(launchEntity)

            if let attachment = attachments.entity(for: "Test") {
                launchEntity = attachment
                content.add(launchEntity)
            }
        } update: { content, attachments in

        } attachments: {
            Attachment(id: "Test", {
                LaunchView()
            })
        }
    }

So the good news is that we don't see duplicate entities in the graph. The bad news is that ViewAttachmentComponent is calling the SwiftUI more than once. I suggest you file a bug with Feedback Assistant. In the meantime, you could using RealityView to create attachments. If your view is just presenting data, then I suppose you could just ignore this.

I can't reproduce this on my end. I just tried a few of my projects and examples and they are working fine. If I add a print line to the make closure of RealityView, I only see it print once. When I inspect the entity graph I see what I expect to see. I'm using visionOS 26 Beta 5 and the latest Xcode.

Some other things to think about. You can use a feature in Xcode to capture the entity hierarchy. When you do this, do you see duplicate entities in the same hierarchy or duplicate hierarchies? https://www.gabrieluribe.me/blog/debugging-realitykit-apps-games-visionos

Is there anything higher up in your SwiftUI stack that could be causing your RealityView to be created more than once?

If you can post some example code showing the issue I may be able to provide more useful help

@radicalappdev , Thanks for your answer!

This is a fragment of my code, which has been modified for demonstration.:

  RealityView { content in
                //...
                launchEntity = createLaunchEntity() //This entity maybe creat two or more
                content.add(launchEntity)
                
            } update: { content in
                //...
            }

 func createLaunchEntity() -> Entity {
                //...
    let entity: Entity = Entity()

let launchviewComponent = ViewAttachmentComponent(
                rootView: LaunchView()
            )
entity.components.set(launchviewComponent) // Creat a UI View to show
                //...

print("Has Creat Test!") // It has been output once.
return entity
}

In this code, "Has Creat Test!" It was output once (This is normal.), But I wrote the print content in onAppaer in LaunchView, it was output many times(This is problem).

If anyone knows the cause of the problem and the solution or other ideas about the problem, I hope you can help me. Thank you!

Accepted Answer

I made a standalone project based on your code check this out. The good news that the entity is not being duplicated. Let's look at the cod first.

struct ImmersiveView: View {

    @State var launchEntity = Entity()

    var body: some View {
        RealityView { content in

            print("RealityView Content Loaded!") // Called Once
            launchEntity = createLaunchEntity()
            content.add(launchEntity)
        }
    }

    func createLaunchEntity() -> Entity {
        //...
        let entity: Entity = Entity()
        entity.name = "Launch Entity"

        let launchviewComponent = ViewAttachmentComponent(
            rootView: LaunchView()
        )
        entity.components.set(launchviewComponent)

        print("createLaunchEntity was called") // Called Once
        return entity
    }
}

struct LaunchView: View {

    var body: some View {
        VStack {

            Text("Launch View")

        }
        .padding()
        .onAppear() {
            print("Launch view appears!") // Called Twice
        }
    }
}

When I load this immersive space I see 4 lines in the console

RealityView Content Loaded!
createLaunchEntity was called
Launch view appears!
Launch view appears!

What happened

  • RealityView content was called once
  • createLaunchEntity
  • The onAppear closure in the LaunchView was called twice.

That made me wonder if ViewAttachmentComponent is calling LaunchView more than once and yes, that appears to be the case.

When I create the attachment using the attachments closure on RealityView, onAppear is only called once.

    var body: some View {
        RealityView { content, attachments in

            print("RealityView Content Loaded!") // Called Once

            content.add(launchEntity)

            if let attachment = attachments.entity(for: "Test") {
                launchEntity = attachment
                content.add(launchEntity)
            }
        } update: { content, attachments in

        } attachments: {
            Attachment(id: "Test", {
                LaunchView()
            })
        }
    }

So the good news is that we don't see duplicate entities in the graph. The bad news is that ViewAttachmentComponent is calling the SwiftUI more than once. I suggest you file a bug with Feedback Assistant. In the meantime, you could using RealityView to create attachments. If your view is just presenting data, then I suppose you could just ignore this.

Thanks you @radicalappdev

I have submitted Feedback:

FB19545353

RealityView content.add Called Twice Automatically
 
 
Q