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

Dismissed on EnvironmentObject change #8

Open
Erhannis opened this issue Dec 31, 2019 · 8 comments
Open

Dismissed on EnvironmentObject change #8

Erhannis opened this issue Dec 31, 2019 · 8 comments

Comments

@Erhannis
Copy link

This library is much more convenient than the default way of doing modals, BUT, we have a view that gets automatically updated once a second or so. (It's tied to an EnvironmentObject.) When this happens, the modal disappears. Ideally, I'd like it to stay visible, and preferably be updated according to the changes which have occurred in the EnvironmentVariable, while the view under the modal is updated in the background. Can this be done?

@diniska
Copy link
Owner

diniska commented Jan 10, 2020

@Erhannis Thanks for your question. Could you please provide an example of your view structure? I'm pretty sure that this can be solved by moving ModalPresenter a few levels above your updated view. The code would be helpful to better understand the problem and give a better answer.

@Erhannis
Copy link
Author

I may be able to make a demo view later, but the actual view in question is company code, so I unfortunately cannot provide the code. In any case, I believe that while testing, I'd placed the ModalPresenter at the top level, or nearly. It was above the modal ModalLink, at least.

I suspect the problem is related to the following in the source comments for "sheet(item:onDismiss:content:)" : "item: a Binding to an optional source of truth for the sheet. [...] If the identity changes, the system will dismiss a currently-presented sheet and replace it by a new sheet." Perhaps the change in an EnvironmentVariable triggers some change in the content, so the system dismisses the sheet, but for some reason doesn't recreate it? I'll try to make a toy example later if I have time.

@Erhannis
Copy link
Author

Erhannis commented Jan 21, 2020

Here's a minimal example demonstrating the problem:

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var eo: EnvObj
    
    var body: some View {
        ModalPresenter {
            ModalLink(destination: Text("Modal")) {
                Text("Button")
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

final class EnvObj: ObservableObject {
    @Published var number: Int64 = 0
    
    init() {
        NSLog("init EnvObj")
        Thread {
            while true {
                Thread.sleep(forTimeInterval: 4.0)
                DispatchQueue.main.async {
                    self.number = self.number + 1
                    NSLog("inc number -> \(self.number)")
                }
            }
        }.start()
    }
}

In SceneDelegate.swift, also change

let contentView = ContentView()

to

let contentView = ContentView().environmentObject(EnvObj())

I think that's all that's required. When you tap Button, the modal should appear correctly, but disappears in 4 seconds or less, when the EnvironmentObject is updated.

The bug occurred on both a physical device and a simulator.

@diniska
Copy link
Owner

diniska commented Jan 21, 2020

@Erhannis thanks for the example. I'm able to reproduce it and going to fix the issue. Until then, you can use the next refactoring as a temporary solution: Leave ModalPresenter inside the ContentView and move the rest into a temporary view.

struct ContentView: View {
    var body: some View {
        ModalPresenter {
            EnvironmentContentView()
        }
    }
}

private struct EnvironmentContentView: View {
    @EnvironmentObject var eo: EnvObj

    var body: some View {
        ModalLink(destination: Text("Modal")) {
            Text("Button")
        }
    }
}

This change leaves ContentView unaffected by changes and thus doesn't dismiss the modal. It also shouldn't have a measurable effect on performance as SwiftUI Views are very cheap.

@Erhannis
Copy link
Author

Erhannis commented Jan 21, 2020 via email

@bark1n9
Copy link

bark1n9 commented May 31, 2020

@diniska Were you able to fix this?

@diniska
Copy link
Owner

diniska commented May 31, 2020

Hello, @bark1n9! My current suggestion is to separate the ModalPresenter and the view that uses EnvironmentObject so that the reload is no triggered. This is a pretty easy refactoring as shown here: #8 (comment).

@bark1n9
Copy link

bark1n9 commented May 31, 2020

@diniska Thank you! I somehow missed that comment :)

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

3 participants