Unable to present another Immersive Space when one is already requested or connected

879 views Asked by At

I'm opening an immersive space:

Button {
    Task{
        await openImmersiveSpace(id: "globe")
    }
} label: {
    Text("Jump to Globe")
}

If I click multiple times I get a warning: Unable to present another Immersive Space when one is already requested or connected

The solution I can think of at present is to create an environment variable to save the state of entering the immersive space, and determine whether it has been entered when the button is clicked.

Globe()
    .onAppear{
        model.isShowGlobe = true
    }
    .onDisappear{
        model.isShowGlobe = false
    }

Button {
    if model.isShowGlobe{
        return
    }
    Task{
        await openImmersiveSpace(id: "globe")
    }
} label: {
    Text("Jump to Globe")
}

Or after I enter the immersive space from the Globe, hide or close the Globe. Do you have any better suggestions?

1

There are 1 answers

0
Andy Jazz On BEST ANSWER

At first, I should say that a visionOS app can display just ONE space at a time. You'll get an error if you try to open a new space while the previous one is visible. To dismiss an open space, use the code below. There's no need to specify an id when dismissing your immersive space because there can only be just one space open at a time.

import SwiftUI

struct DismissImmersiveness : View {
    @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace

    var body: some View {
        Button("Close Immersive Space") {
            Task {
                await dismissImmersiveSpace()
            }
        }
    }
}

However, the most robust approach in your case is to have just one button, switching it from the True state to the False state. This is what it looks like:

import SwiftUI
import RealityKit

struct ContentView: View {
    @Environment(\.openImmersiveSpace) var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace
    @State var isPressed = false
    @State var immersiveSpaceIsVisible = false

    var body: some View {
        VStack {
            RealityView { content in /* RealityKit scene */ }
            
            Button(isPressed ? "Space Opened" : "Space Closed") {
                isPressed.toggle()
            }.foregroundColor(isPressed ? .green : .red)
        }
        .onChange(of: isPressed) { (_, new) in
            Task {
                if new {
                    switch await openImmersiveSpace(id: "ImmersiveSpace") {
                        case .opened: immersiveSpaceIsVisible = true
                        case .error: fallthrough
                        case .userCancelled: fallthrough
                        @unknown default: immersiveSpaceIsVisible = false
                    }
                } else if immersiveSpaceIsVisible {
                    await dismissImmersiveSpace()
                    immersiveSpaceIsVisible = false
                }
            }
        }
    }
}

enter image description here

P. S.

Also, the Unable to present another Immersive Space when one is already requested or connected error appears in cases where you simultaneously call Immersion Space from the ContentView and from the App files.