swiftui how to apply usage of multiple StateObject

88 Views Asked by At

prettyNew to SwiftUi and combine, how could be possible having more than one class initialized and accessible in the whole app? This code is not working, when I tap the button I get the error about

Thread 1: Fatal error: No ObservableObject of type OneSharedClass found. A View.environmentObject(_:) for OneSharedClass may be missing as an ancestor of this view.

which is the right way to use them?I'd like these two classes could be talk, ut with no retain circles.

import SwiftUI

@main
struct SharingData: App {

    @StateObject var oneSharedClass = OneSharedClass()
    @StateObject var otherSharedClass = OtherSharedClass()

    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(oneSharedClass)
                .environmentObject(otherSharedClass)

        }
    }
}

//Code for the rest of the app


import SwiftUI

struct ContentView: View {
   
    @EnvironmentObject var oneSharedClass: OneSharedClass
    @EnvironmentObject var otherSharedClass: OtherSharedClass

    var body: some View {
        VStack(spacing: 10) {
            Text("name: \(oneSharedClass.name) \(oneSharedClass.isLogged ? "✅" : "❌")")
            
            Button("Tap") {
                otherSharedClass.testFunc()
            }
        }
    }
}

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

class OneSharedClass: ObservableObject {
    
    @Published var name: String = "N/D"
    @Published var isLogged: Bool = true
}


class OtherSharedClass: ObservableObject {
    
    @EnvironmentObject var oneSharedClass: OneSharedClass
    
    @State var myArray = ["Harry", "Ron", "Hermione"]
    
    func testFunc() {
        if oneSharedClass.isLogged {
            print(myArray)
        }
    }
    
}

UPDATE: version where I pass the reference to a single method, so the otherSharedClass remains independent, but not sure if @StateObject in "App" is required.

import SwiftUI

@main
struct SharingData: App {
    
    /*@StateObject*/ var oneSharedClass = OneSharedClass()
    /*@StateObject*/ var otherSharedClass = OtherSharedClass()
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(oneSharedClass)
                .environmentObject(otherSharedClass)
        }
    }
}

struct ContentView: View {
    
    @EnvironmentObject var oneSharedClass: OneSharedClass
    @EnvironmentObject var otherSharedClass: OtherSharedClass
    
    var body: some View {
        
        VStack(spacing: 10) {
            
            Text("name: \(oneSharedClass.name) \(oneSharedClass.isLogged ? "✅" : "❌")")
                .background(oneSharedClass.myColor)
            
            Button("Tap oneSharedClass") {
                oneSharedClass.testFunc()
                otherSharedClass.testFunc(oneSharedClass: oneSharedClass)
            }
            
        }
    }
}

class OneSharedClass: ObservableObject {
    
    @Published var name: String = "N/D"
    @Published var isLogged: Bool = true
    
    @Published var myColor: Color = Color.red
    
    func testFunc() {
        isLogged.toggle()
    }
}


class OtherSharedClass: ObservableObject {
    
    @Published var myArray = ["Harry", "Ron", "Hermione"]
    
    func testFunc(oneSharedClass: OneSharedClass) {
        print("isLogged read from oneSharedClass and printed from other: \(oneSharedClass.isLogged)")
        print(myArray)
        oneSharedClass.myColor = oneSharedClass.myColor == .green ? .red : .green
    }
    
}
1

There are 1 best solutions below

5
On BEST ANSWER

EnvironmentObject and State are only for SwiftUI views you cannot use the property wrappers in a class.

Change State to Published.

And you can pass the other as an argument when needed

func testFunc(onesharedclass: OneSharedClass)

If you want to share a class with an entire app you have to change your approach and disconnect the value of a class from the UI.

https://www.avanderlee.com/swift/dependency-injection/