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
}
}
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.