nalexn / clean-architecture-swiftui

SwiftUI sample app using Clean Architecture. Examples of working with CoreData persistence, networking, dependency injection, unit testing, and more.
MIT License
5.56k stars 671 forks source link

Question: why `case .isLoading` is not called even we got `.isLoading` on didSet? #76

Open mitolog opened 2 years ago

mitolog commented 2 years ago

Hi, thanks for sharing and committing such a great project.

While using your architecture, I found that the the scope below is not always called:

https://github.com/nalexn/clean-architecture-swiftui/blob/9f2a98a7146f2e28fe44c53d3b9f20620f203baa/CountriesSwiftUI/UI/Screens/CountryDetails/CountryDetails.swift#L28-L29

even though you did setIsLoading at below:

https://github.com/nalexn/clean-architecture-swiftui/blob/9f2a98a7146f2e28fe44c53d3b9f20620f203baa/CountriesSwiftUI/Services/CountriesService.swift#L68

Is this behavior intended?

What I'm expecting is that the loading view will be shown if you enter the view every time. But, it's not.


I've also checked actual value with

        @Published var details: Loadable<Country.Details> {
            willSet{
                print("willSet (\(details) -> \(newValue))")
            }
            didSet {
                print("didSet (\(oldValue) -> \(details))")
            }
        }

then I got

willSet (notRequested -> isLoading(last: nil, cancelBag: CountriesSwiftUI.CancelBag))
didSet (notRequested -> isLoading(last: nil, cancelBag: CountriesSwiftUI.CancelBag))
willSet (isLoading(last: nil, cancelBag: CountriesSwiftUI.CancelBag) -> loaded(CountriesSwiftUI.Country.Details(...)
didSet (isLoading(last: nil, cancelBag: CountriesSwiftUI.CancelBag) -> loaded(CountriesSwiftUI.Country.Details(...)

so I expected CountryDetails.swift#L29 to be run, but it's not.

It may be very basic behavior or just an overlook of me but I appreciate anyone's help.

mitolog commented 2 years ago

As I looked definition of wrappedValue , I found notation below:

    /// When a mutable binding value changes, the new value is immediately
    /// available. However, updates to a view displaying the value happens
    /// asynchronously, so the view may not show the change immediately.
    public var wrappedValue: Value { get nonmutating set }

Is this the reason why?

p.s. If I set ensureTimeSpan before sinkToLoadable , then set time interval to 1.5 , it works as expected.