Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why changes made to a @Published variable do not affect the while-loop condition?

Description

I have two classes, one of them is implemented using the singleton pattern:

class Singleton: ObservableObject {
    static let sharedSingleton = Singleton()
    private init() {}
    
    @Published var fetchingData = true

    // This is called upon launching the app
    func getData() {
        fetchingData = true
        someNetworkingCalls {
          ... // fetching data from a db
          self.fetchingData = false
        }
    }
}

Then, I have another class that has a function where a while-loop is used to pause the code execution if the Singleton class is fetching data:

class AnotherClass: ObservableObject {
    private var sharedSingleton = Singleton.sharedSingleton
    func getAnotherData() {
        while (sharedSingleton.fetchingData){// do nothing here}
        
        // then proceed execute another networking call

    }
}

Functions from both classes are being called in MainAppView in the following fashion:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@ObservedObject singleton = Singleton.sharedSingleton
@StateObject anotherClass = AnotherClass()
...
SomeView()
 .task {
     singleton.getData()
     anotherClass.getAnotherData()
  }
  .environmentObject(anotherClass)
...

Problem

The while-loop never terminates even though I’m sure the fetchingData has been set to false.

I could mitigate this problem by wrapping anotherClass.getAnotherData() in an asyncAfter but I highly suspect that it worked only because by the time getAnotherData() is called, the singleton.getData() has already finished its job — this could be very tricky if users have unstable/slow network connections.

I was wondering why the while-loop cannot catch the change made to the @Published var? And how to properly solve this problem?

>Solution :

A while loop is not a reliable way to wait for data to be loaded. Instead, one solution would be to use Combine to watch for changes to the fetchingData Publisher.

That might look like this:

import Combine

class AnotherClass: ObservableObject {
    private var sharedSingleton = Singleton.sharedSingleton
    
    private var cancellable : AnyCancellable?
    
    func getAnotherData() {
        cancellable = sharedSingleton.$fetchingData.sink { value in
            guard value else { return }
            //do your next action here
        }
    }
}

Realistically, it would be better to watch whatever the data itself is, rather than setting up a separate fetchingData. That might look like this:

class Singleton: ObservableObject {
    static let sharedSingleton = Singleton()
    private init() {}
    
    @Published var data : Data? = nil

    // This is called upon launching the app
    func getData() {
        someNetworkingCalls { result in
            self.data = result
        }
    }
}

class AnotherClass: ObservableObject {
    private var sharedSingleton = Singleton.sharedSingleton
    
    private var cancellable : AnyCancellable?
    
    func getAnotherData() {
        cancellable = sharedSingleton.$data.sink { data in
            guard let data = data else { return }
            //do your next action here that depends on `data`
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading