Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Attempt to present toast whose view is not in the window hierarchy #19

Closed
OccultSlolem opened this issue Jan 23, 2021 · 7 comments
Closed
Labels
bug Something isn't working help wanted Extra attention is needed

Comments

@OccultSlolem
Copy link

OccultSlolem commented Jan 23, 2021

Pre-requisites:

  • [*] Yes, I looked through both open and closed issues looking for what I needed.
  • [*] No, I did not find what I was looking for.

When attempting to trigger a toast to appear programmatically, I get the following error:

[Presentation] Attempt to present <_TtGC7ToastUI26ToastViewHostingControllerGV7SwiftUI15ModifiedContentGVS_9ToastViewVS1_9EmptyViewVS1_4TextS4__GVS1_30_EnvironmentKeyWritingModifierVS_17AnyToastViewStyle___: 0x10193f040> on <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x104f11380> (from <_TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView_: 0x104f11380>) whose view is not in the window hierarchy.

The relevant section of my code looks like this:

@State private var presentingToast = false
@State private var uploadProgress = 0.0
var body: some View {
    VStack {
        Button(action: {
            print("Show toast")
        }, label: {
            Text("")
        })
        .toast(isPresented: $presentingToast) {
            ToastView("Uploading...")
                .toastViewStyle(DefiniteProgressToastViewStyle(value: $uploadProgress))
        }
        .hidden()
   

When I set presentingToast to true, it gives me the aforementioned error. I've also tried removing the hidden modifier and putting in some words in the Text, but that doesn't make a difference.

Your Environment

  • Swift Version: 5
  • Xcode Version: 12.3
  • Operating System Version: macOS Big Sur 11.1
  • Device or Simulator: iPhone 8 Plus
@OccultSlolem OccultSlolem added bug Something isn't working help wanted Extra attention is needed labels Jan 23, 2021
@quanshousio
Copy link
Owner

It seems to me that you're creating a dummy hidden button just to attach the .toast modifier, and then trigger the toast somewhere else, right? Would you mind providing more information about what you're trying to accomplish here? How did you trigger the toast programmatically?

@OccultSlolem
Copy link
Author

OccultSlolem commented Jan 25, 2021

Yep, that's correct. The gist of the situation is that this toast is for a View where a user can upload an image to Firebase Storage, however before the toast is presented it verifies that the photo is correctly formatted. If it isn't, then it shows an alert (which I've also set to be programmatically triggered in almost the exact same way, tying it to a dummy hidden button. It goes something like this:

@State private var presentingToast = false
@State private var uploadProgress = 0.0
var body: some View {
    VStack {
        Button(action: {
            print("Show toast")
        }, label: {
            Text("")
        })
        .toast(isPresented: $presentingToast) {
            ToastView("Uploading...")
                .toastViewStyle(DefiniteProgressToastViewStyle(value: $uploadProgress))
        }
        .hidden()
...
}

//Function gets called after an ImagePicker is dismissed
func loadImage() {
    guard let inputImage = inputImage else { return } //This is pulled from an ImagePicker sheet set up elsewhere
    local data = inputImage.pngData()!
    //Do other checks on the image...
    ...
    //If all checks are OK
    presentingToast = true //In theory, the toast should present itself here, but the aforementioned error happens here (when I step to this line in the debugger, this is where the error pops itself up)
    ...
}

@quanshousio
Copy link
Owner

How did you implement the callback after the user has picked an image? Are you calling your loadImage() after the picker has been successfully dismissed? I'm guessing the error might due to the picker hasn't been dismissed yet, so we are prematurely presenting the toast.

@OccultSlolem
Copy link
Author

OccultSlolem commented Jan 26, 2021

It's tied to the onDismiss parameter of the sheet modifier

@State private var showingImagePicker = false
@State private var inputImage: UIImage?
...

var body: some View {
    VStack(alignment: .leading) {
        ...
        Button(action: {
            showingImagePicker = true
        }, label: {
            Text("Upload photo")
            Image(systemName: "chevron.right")
        })
        ...
    }
    .sheet(isPresented: $showingImagePicker, onDismiss: loadImage) {
        ImagePicker(image: self.$inputImage)
    }
}

func loadImage() {
    ...
}

@quanshousio
Copy link
Owner

Try calling your function using onDisappear modifier on ImagePicker view instead.

.sheet(isPresented: $showingImagePicker) {
  ImagePicker(image: $inputImage)
    .onDisappear {
      loadImage()
    }
}

Would you mind showing me how do you implement the ImagePicker? Are you calling presentationMode.wrappedValue.dismiss() in imagePickerController(_:didFinishPickingMediaWithInfo:) delegate method of UIImagePickerController to dismiss the picker after the user has picked an image?

@OccultSlolem
Copy link
Author

Ah, yep, that did the trick. Thanks so much!

As for the ImagePicker, it's pretty much exactly as you said. I have a UIViewControllerRepresentable struct that has a Coordinator class inside it that instantiates an ImagePicker in its constructor, and then on the imagePickerController(_:didFinishPickingMediaWithInfo:) it calls the dismiss method on that ImagePicker.

@quanshousio
Copy link
Owner

By calling presentationMode.wrappedValue.dismiss(), it immediately fires onDismiss callback of the sheet modifier, but at that time UIImagePickerController has not been successfully dismissed, hence the error. Using onDisappear will ensure the view has been successfully dismissed (the same as viewDidDisappear in UIKit). I'm glad it helped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants