简体   繁体   中英

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() { }
}

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.

First, make LoadingSingleton a class that adheres to the ObservableObject protocol. Use the @Published property wrapper on isLoading so that your SwiftUI views update when it's changed.

class LoadingSingleton: ObservableObject {
    @Published var isLoading = false
}

Then, put LoadingSingleton in your SceneDelegate and hook it into your SwiftUI views via environmentObject() :

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?
    static let singleton = LoadingSingleton()

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        let contentView = ContentView()

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView.environmentObject(SceneDelegate.singleton))
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

To enable your SwiftUI views to update when changing isLoading , declare a variable in the view's struct, like this:

struct MyView: View {
    @EnvironmentObject var singleton: LoadingSingleton

    var body: some View {
        //Do something with singleton.isLoading
    }
}

When you want to change the value of isLoading , just access it via SceneDelegate.singleton.isLoading , or, inside a SwiftUI view, via singleton.isLoading .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM