Closed LucasCarioca closed 4 years ago
Although I couldn't exactly reproduce your bug on iOS 13.6, I came across another bug that also related to dismissing toast. I'm currently investigating and will push a fix later. Thanks for your report.
For temporary workaround, you can try using toast()
without ToastView
or view that uses cocoaBlur()
.
I did some debugging locally with the ToastUI code and isolated the issue to this:
let keyWindow = UIApplication.shared.windows.first { $0.isKeyWindow }
var rootViewController = keyWindow?.rootViewController
...
let toastAlreadyPresented = rootViewController is ToastViewHostingController<QTContent>
It never evaluated to true when running on my iOS 13 device but does as expected on iOS 14 Simulator and Device.
I also tried adding the dismiss here and it does dismiss the toast but the app crashes right after.
if let dismissAfter = dismissAfter {
DispatchQueue.main.asyncAfter(deadline: .now() + dismissAfter) {
self.isPresented = false
}
}
I also tried without the ToastView like you suggested and its the same issue. The root cause is in the modifier so that's called with or without the view. I could roll my own modifier for it which I may do just to get this out but I was trying to see if I could help resolve this.
Actually some more digging and Its caused by the .onPreferenceChange(...)
not kicking off when the isPresented
value changes.
ToastViewModifier.swift: ToastViewIsPresentedModifier: body
internal func body(content: Content) -> some View {
content
.preference(key: ToastViewPreferenceKey.self, value: isPresented)
.onPreferenceChange(ToastViewPreferenceKey.self) {
self.present($0)
}
}
It never evaluated to true when running on my iOS 13 device but does as expected on iOS 14 Simulator and Device.
Can you set a breakpoint at that expression after the toast is showing and po rootViewController
? The debugger should outputs something like this:
(lldb) po rootViewController
▿ Optional<UIViewController>
▿ some : <_TtGC7SwiftUI19UIHostingControllerV17ToastUISample_iOS11ContentView_: 0x7fef5e511970>
That expression simply checks if the topmost view controller is currently our UIHostingController
showing the toast or not, and it should evaluates to true
in that case.
I also tried adding the dismiss here and it does dismiss the toast but the app crashes right after.
I'm not understand what you meant here as it's identical to what we're having right now https://github.com/quanshousio/ToastUI/blob/42c4682363bfe8a762967e460978230df27d5c32/Sources/ToastUI/ToastViewModifier.swift#L42-L46
I also tried without the ToastView like you suggested and its the same issue. The root cause is in the modifier so that's called with or without the view. I could roll my own modifier for it which I may do just to get this out but I was trying to see if I could help resolve this.
Thank you for your information. I'm still trying to figure out what's the culprit here. It seems the app crashes right away when the toast dismisses due to the invalid usage of animating the blurred effect. I just pushed a fix on hotfix-1.0.2
branch, can you check that out to see if it works?
Actually some more digging and Its caused by the
.onPreferenceChange(...)
not kicking off when theisPresented
value changes.
If that so, I'm doubting that this might be a SwiftUI bug. However, it's irritating that the bug happens on your device/simulator but not mine. Does your view belong to a bigger view hierarchy, or it just a simple VStack
like you gave in the first example?
Thank you so much for taking your time, I really appreciate it. Hopefully we can get this fixed as quickly as possible.
Yeah the view itself is just a simple VStack it is being shown by a parent NavigationView (app drawer). To rule out any possible conflict there I also tried starting the app with that simple view as the main content view of the app and it still happens.
Just to clarify I have tried this in the following ways:
✅ = it worked ❌ = it didn't work
The only common thing I can tell is iOS13 vs iOS14.
Probably not as intended but I did get it to work using your hotfix
branch. I pulled it down and made one small change and now it works. I think this kind of breaks other functionality you have though.
if let dismissAfter = dismissAfter {
DispatchQueue.main.asyncAfter(deadline: .now() + dismissAfter) {
self.isPresented = false
rootViewController?.dismiss(animated: true) // <-----ADDED THIS
}
}
Also without changing your code I got it working with the following:
.toast(isPresented: $showWarning) {
ToastView{
VStack {
...
Button(action: {
self.showWarning = false
let keyWindow = UIApplication.shared.windows.first { $0.isKeyWindow }
let rootViewController = keyWindow?.rootViewController
rootViewController?.dismiss(animated: true)
}) {
Text("OK")
}
}
}
}
Unfortunately, I still couldn't reproduce the bug. I currently don't have macOS 11.0 installed but I've tried all the following environments on latest macOS 10.15.6:
IOS13.6.1. Its very strange that its only happening that device. I’ll get ahold of another device to test on and make sure its not something strange with that.
If you want go ahead and lets consider that hotfix
a resolution to this issue since it gives me at least a workaround. As long as it gets merged. I’ll look a little further into it on my end and if I can come up with a better way recreating it I’ll open a new issues with more information.
Thanks for taking the time to look into this!
No problem. Sorry for a little slow response as I'm still trying to figure out all the possible ways to reproduce this. By the way, have you tried cleaning the build folder, build from scratch and reinstall the application?
I’ll give that a shot but no need to keep this open. I would just close this when that hotfix is merged.
Also no worries on response, you have actually been responding very quickly! 👍
I just merged hotfix-1.0.2
into master
. Keep me update as I want this issue to be completely resolved.
@quanshousio fyi, I have not found out what the problem was yet but it has nothing to do with your code. I must be doing something strange with my views and not realizing it. I used the toast in a different location and it works fine out of the box. Just thought you should know.
Also I love this project thanks for putting it together.
I'm glad it's working now, though I still feel weird that SwiftUI fails to call .onPreferenceChange()
in some circumstances. Thank you so much for your support.
Pre-requisites:
I am trying to switch from my basic alerts to using ToastUI but I'm running into an issue. For some reason my toast won't dismiss even after the set
dismissAfter
time. Funny enough this is only an issue when running on a device with iOS <14. Seems like thedismissAfter
functionality only works with the beta.Expected Behavior
Should dismiss after the pre-defined time.
Current Behavior
Toast stays on the screen and dismiss is never called.
Possible Solution
Steps to Reproduce (for bugs)
Context
Your Environment