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

Screen is dismissed twice when swiping down on a sheet #64

Closed
rdonnelly opened this issue Nov 2, 2023 · 9 comments
Closed

Screen is dismissed twice when swiping down on a sheet #64

rdonnelly opened this issue Nov 2, 2023 · 9 comments

Comments

@rdonnelly
Copy link

Hi there! I am admittedly pretty green with iOS development and the framework, but learning lots and having fun. I'm running into some interesting behavior when playing with mixing navigation types. Basically, if I push a screen onto the stack, then presentSheet another screen, then dismiss the sheet with a swipe down, I get a double dismiss animation:

Manually dismissing the sheet works just fine. I built a small repro app to see the behavior:

https://github.com/rdonnelly/FlowStacksDoubleDismiss

Definitely willing to consider other approaches if something seems fishy in the code! Thanks!

@johnpatrickmorgan
Copy link
Owner

Thanks for raising this @rdonnelly ! This seems to be an issue introduced in iOS 17 when using view models - I was able to reproduce the issue in the project's demo app. I'll need to dig a bit deeper to understand what's going on, so thank you for the clear reproduction.

@rdonnelly
Copy link
Author

Awesome, thanks for the confirmation and for taking a look, @johnpatrickmorgan! And obviously no rush, definitely digging the library and approach! 👏

@tarikstafford
Copy link

I had a similar issue with a navigationView wrapping a tabView when the app moves to background it pops and/or pushes and then pops.

@wickwirew
Copy link

wickwirew commented Dec 4, 2023

@johnpatrickmorgan any ideas what is causing this? I spent a few hours the other day trying to dig into it but came up empty. Tried a bunch of different things but wasnt able to get it to stop. Happy to continue to dig more! Just curious if you had any ideas or a hunch about whats going on. Btw huge thanks for the library!

@johnpatrickmorgan
Copy link
Owner

Thanks a lot @wickwirew for looking into this - I've also been stumped. One thing I tried was adding a Binding wrapper to log the get and set:

extension Binding {
  
  func withLogging<T>(_ transform: @escaping (Value) -> T) -> Binding {
    return Binding(
      get: {
        print("getting \(transform(wrappedValue))")
        return wrappedValue
      },
      set: { newValue in
        print("setting from \(transform(wrappedValue)) to \(transform(newValue))")
        wrappedValue = newValue
      }
    )
  }
}

And then initialising the Router with Router($viewModel.routes.withLogging({ $0.count })). Doing so showed that the Binding is somehow giving a stale value:

setting from 3 to 2
VMCoordinator: _viewModel changed.
getting 2
getting 2
getting 2
getting 3 // !!!
getting 2
getting 2

But I haven't been able to figure out why yet.

@wickwirew
Copy link

wickwirew commented Dec 6, 2023

Huh strange, I actually did something similar and got different results. In the AppCoordinatorView created a wrapped binding to pass to the Router:

var binding: Binding<Routes<Screen>> {
    Binding {
        print("getting: \(coordinatorViewModel.routes.count)")
        return coordinatorViewModel.routes
    } set: { newValue in
        print("setting from \(coordinatorViewModel.routes.count) to \(newValue.count)")
        coordinatorViewModel.routes = newValue
    }
}

Which logs the correct values. Which I guess makes since its reading directly from the source of truth. Very weird the extension prints an old value though.

setting from 3 to 2
getting: 2
getting: 2
getting: 2
getting: 2
getting: 2
getting: 2
getting: 2

I was able to replicate what you saw with that Binding extension too. It looks like when the stale value is printed its not from SwiftUI reading the value, but actually in the isActiveBinding setter reading the allRoutes.wrappedValue. The stale value has to be related though. It only happens when the dismissal bug shows, and not for every sheet.

@lionel-alves
Copy link

I am having the same issue, it is really annoying. Any way to work around it?

@johnpatrickmorgan
Copy link
Owner

I've tracked down the problem to the addition of the FlowNavigator as an environment object:

.environmentObject(FlowNavigator($routes))

Removing that line avoids the issue. But strangely, it seems to also be overcome by just observing the flow navigator in Node. To do so, I have to refactor Node into a struct rather than an enum, which is a bit long-winded but I'm in the process of doing so.

@johnpatrickmorgan
Copy link
Owner

I've refactored Node in such a way that I believe this issue is now fixed. It's available in version 0.4.0. Please let me know if you have any issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants