5

I have this code and would expected a b as Text.

Result: a a -> see screenshot. What am I doing wrong?

import SwiftUI

class PublishString : ObservableObject {

    init(string: String) {
        self.string = string
        print(self.string)
    }

    @Published var string : String = "a"
}

struct ContentView: View {

    @EnvironmentObject var text1 : PublishString
    @EnvironmentObject var text2 : PublishString

    var body: some View {
        VStack {
            Text(text1.string)
            Text(text2.string)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(PublishString(string: "a"))
        .environmentObject(PublishString(string: "b"))
    }
}

enter image description here

and ...this works:

class PublishString : ObservableObject {

    init(string: String) {
        self.string = string
        print(self.string)
    }

    @Published var string : String = "a"
}

class PublishString2 : ObservableObject {

    init(string: String) {
        self.string = string
        print(self.string)
    }

    @Published var string : String = "a"
}

struct ContentView: View {

    @EnvironmentObject var text1 : PublishString
    @EnvironmentObject var text2 : PublishString2

    var body: some View {
        VStack {
            Text(text1.string)
            Text(text2.string)
        }
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Chris
  • 7,579
  • 3
  • 18
  • 38

2 Answers2

3

As noted by Asperi in the comment, SwiftUI identifies Environment Objects by the type (the class definition you have used). It looks for an object of that type and uses the first one it finds.

One option is to have multiple properties on the one object that you can access (this would mean two separate String properties in your case.

Further information is available on the Apple documentation.

Chris
  • 4,009
  • 3
  • 21
  • 52
  • And if I want to reuse a component which uses this class as environmentobject? Then i cannot use more than one instance if it? – Chris May 14 '20 at 20:15
  • @Chris Yes, although a different instance could be injected into an ancestor view for use in a different part of the app. As far as I know that is ok (provided no view has two "upstream" environment objects of the same class. – Chris May 14 '20 at 20:16
  • @Chris I found this answer, which provides a way like this, using two properties of a single object: https://stackoverflow.com/a/57366566/8289095 – Chris May 14 '20 at 20:34
0

The accepted answer is perfectly fine and correct and answers the question.

The following is a simple workaround, if you must use two EnvironmentObjects of the same type to be passed around within your app, and stumble upon this question:

You can make a second class that inherits everything from the first class. Therefore you avoid redundancy and can use both EnvironmentObjects separately.

class PublishString : ObservableObject {

    init(string: String) {
        self.string = string
        print(self.string)
    }

    @Published var string : String = "a"
}

class PublishString2 : PublishString {}

struct ContentView: View {

    @EnvironmentObject var text1 : PublishString
    @EnvironmentObject var text2 : PublishString2

    var body: some View {
        VStack {
            Text(text1.string)
            Text(text2.string)
        }
    }
}

instantiation:

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView().environmentObject(PublishString(string: "a"))
        .environmentObject(PublishString2(string: "b"))
    }
}
Patrick Michiels
  • 239
  • 4
  • 13