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

Xcode 12 GM warnings when updating local state from AppState #38

Open
NeverwinterMoon opened this issue Sep 16, 2020 · 5 comments
Open

Comments

@NeverwinterMoon
Copy link

NeverwinterMoon commented Sep 16, 2020

Not sure how critical this is, I just jumped into Xcode 12 GM today, but I have loads of warnings which were not there with Xcode 11. Once again, not sure it actually affects anything, but maybe worth mentioning.

Basically, all the local state updates which come from the injected AppState updates are marked like this:

image

Maybe it makes sense to use the new onChange(of:perform:) API?

@nalexn
Copy link
Owner

nalexn commented Sep 17, 2020

These warnings cannot be ignored, we should find the cause.

I can assume you have some code in your project that updates the AppState while the view is being rendered: an example.

I double-checked the sample project with the new Xcode and it doesn't throw these warnings, and using onReceive for updating the local view state should be perfectly legit.

You can try to put a breakpoint in the AppState update to find the call trace originating from SwiftUI render cycle

@NeverwinterMoon
Copy link
Author

NeverwinterMoon commented Oct 12, 2020

My only culprit for something like you mentioned would be the use of willSet/didSet, but I don't even have those around the view I get the warnings at. But I did manage to find a connection between those warnings and the navigation. When I navigate to the view and do anything around it, there are no warnings. When I navigate one step deeper down the navigation stack and then return to the view in question, I immediately get those warnings.

Oh, and I can't reproduce this with iOS 13 with the same code. Only 14.x

OK, I managed to reproduce the problem with minimal changes in your project: NeverwinterMoon@a98fd5f

The actual problem manifests in broken navigation (automatic navigation back), but this is also when I get the warnings mentioned above...

Steps:

  • Load the app

  • Tap on "Afghanistan"

  • Tap on the flag cell (anywhere around the flag image)

  • Tap "Go to BLUE"

  • Tap "Back"

  • Tap "Back" ("< Afghanistan")

  • Tap "Back" ("< Countries")

We are on the initial page again

  • Tap "Afghanistan"
  • Tap on the flag cell (anywhere around the flag image)
  • Observe (opens the new view and then automatically navigates back)

The above is 100% reproducible with iOS 14 and not reproducible with iOS 13.

ezgif-7-3864e0a2983a

It looks like the issue is at Binding#onSet. The same type of navigation works just fine using @State variables.

This routing approach was done to handle deep linking comfortable, but maybe now with iOS 14's onOpenURL that can be attached to any view it might make sense to use a different one?

@NeverwinterMoon
Copy link
Author

OK, I did tangle everything together. So I'll go step by step.

First of all, I have this navigation: View1 -> View2 -> View3 -> View4

The original problem

The warnings - they are actually caused by having this on View2:

.onAppear {
   $someStateVar.wrappedValue = someValueFromUserDefaults
}

I also tried to wrap the above in DispatchQueue.main.async and it didn't help.

Interestingly enough, when I go: View1 -> View2, there are no warnings.
When I got View1 -> View2 -> View3 -> back to View2, the warnings pop up.
Most importantly, this is only with iOS 14, no warnings on iOS 13 with exactly the same code.

The navigation problem

This one is a bummer. I managed to reproduce it in your project as well, as I wrote above. It's specific only to iOS 14 and works just fine with iOS 13. Basically, if the navigation is deeper than 3 views, the routing approach (with the routingBinding) breaks.

I am fine with using the new to iOS 14 onOpenURL, as it allows to attach URL handling logic granularly to every view, which is great, but I still need to support iOS 13 somehow... So I am a bit stuck.

@nalexn
Copy link
Owner

nalexn commented Oct 17, 2020

Yeah, I was hoping programmatic navigation will become less buggy with the iOS update, but it looks like things got only worse.

I'll experiment more with your commit and try to find a workaround. I can see one way to unblock you if you're actively working on some project, but this involves quite some refactoring.

I recently wrote an article, where I concluded that for now, I wouldn't trust SwiftUI with programmatic routing and suggested to use UIKit for navigation, while keeping all the screens written in pure SwiftUI. Consider taking this approach. There is also a project for reference.

@NeverwinterMoon
Copy link
Author

NeverwinterMoon commented Oct 19, 2020

Looks like a nice approach, that https://github.com/nalexn/uikit-swiftui. I wish I'd used that to begin with. I'll try it out at some point and see how it fits the project.

For now, I went with something like @StateObject private var routing = GlobalRouting() just for iOS 14. That was an easy change to make...

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

2 participants