Search code examples
swiftuistructsingleton

How to create a singleton that I can update in SwiftUI


I want to create a global variable for showing a loadingView. I tried lots of different ways but could not figure out how to. I need to be able to access this variable across the entire application and update the MotherView file when I change the boolean for the singleton.

struct MotherView: View {
    
    @StateObject var viewRouter = ViewRouter()
        
    var body: some View {
        
        if isLoading { //isLoading needs to be on a singleton instance
            Loading()
        }

        
        switch viewRouter.currentPage {
        case .page1:
            ContentView()
        case .page2:
            PostList()
        }
    }
}

struct MotherView_Previews: PreviewProvider {
    static var previews: some View {
        MotherView(viewRouter: ViewRouter())
    }
}

I have tried the below singleton but it does not let me update the shared instance? How do I update a singleton instance?

struct LoadingSingleton {
    static let shared = LoadingSingleton()
    var isLoading = false

    private init() { }
}

Solution

  • Make your singleton a ObservableObject with @Published properties:

    struct ContentView: View {
        @StateObject var loading = LoadingSingleton.shared
        
        var body: some View {
            if loading.isLoading {
                Text("Loading...")
            }
            ChildView()
            Button(action: { loading.isLoading.toggle() }) {
                Text("Toggle loading")
            }
        }
    }
    
    struct ChildView : View {
        @StateObject var loading = LoadingSingleton.shared
    
        var body: some View {
            if loading.isLoading {
                Text("Child is loading")
            }
        }
    }
    
    class LoadingSingleton : ObservableObject {
        static let shared = LoadingSingleton()
        @Published var isLoading = false
        
        private init() { }
    }
    

    I should mention that in SwiftUI, it's common to use .environmentObject to pass a dependency through the view hierarchy rather than using a singleton -- it might be worth looking into.