UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

Multiple environmentObject of same type

Forums > SwiftUI

Hey,

If I have two object of same type: Exposure, ExposureA and ExposureB I want to have two environmentObjects but as I know @EnvironmentObject property wrapper searches for Exposure type in environment object and finds the one with the same type as the defined variable. How can I have two objects of the same type as environmentObjects?

Thanks,

Hadi

2      

Maybe this approach will work out in your case

class StateA: ObservableObject {
  @Published var exposure = Exposure()
}

class StateB: ObservableObject {
  @Published var exposure = Exposure()
}

class ExposureState: ObservableObject {
  var stateA = StateA()
  var stateB = StateB()
}

// To inject into ContentView

var exposureState = ExposureState()

ContentView()
          .environmentObject(exposureState.stateA)
          .environmentObject(exposureState.stateB)

2      

hi,

i think @ygeras's approach works in the sense that you can introduce two observable objects of different types, the sole purpose of each being to provide a "wrapper" of an object of type Exposure, and thus you can inject them into the environment as different types.

but i'd recommend some changes. for example, although each may have a @Published reference to an object of type Exposure, that reference will never change ... thus the @Published property wrapper has no effect.

rather, you want to use a little Combine technology so that each of the StateA and StateB objects listens to its Exposure instance for changes and then rebroadcasts those changes as its own. you can do this on StateA with this (repeat for StateB)

import Combine

class StateA: ObservableObject {
  var exposure: Exposure
  private var cancellables = Set<AnyCancellable>()

  init() {
  exposure = Exposure()
  exposure.objectWillChange
            .sink { [self] _ in
                objectWillChange.send() // this makes StateA publish its own change whenever exposure changes
            }
            .store(in: &cancellables)
  }

}

i'd also recommend that you make exposureState a @StateObject:

@StateObject private var exposureState = ExposureState()

hope that helps,

DMG

3      

//https://jaredsinclair.com/2020/05/07/swiftui-cheat-sheet.html?utm_campaign=%20SwiftUI%20Weekly&utm_medium=email&utm_source=Revue%20newsletter
//https://github.com/jaredsinclair/swiftui-property-wrappers/blob/master/Testo/DistinctObjectsExample.swift

import SwiftUI

struct DistinctObjectsExample: View {

    @DistinctEnvironmentObject(\.posts) var postsService: Microservice
    @DistinctEnvironmentObject(\.users) var usersService: Microservice
    @DistinctEnvironmentObject(\.channels) var channelsService: Microservice

    var body: some View {
        Form {
            Section(header: Text("Posts")) {
                List(postsService.content, id: \.self) {
                    Text($0)
                }
            }

            Section(header: Text("Users")) {
                List(usersService.content, id: \.self) {
                    Text($0)
                }
            }

            Section(header: Text("Channels")) {
                List(channelsService.content, id: \.self) {
                    Text($0)
                }
            }
        }.onAppear(perform: fetchContent)
    }

    func fetchContent() {
        postsService.fetchContent()
        usersService.fetchContent()
        channelsService.fetchContent()
    }
}

// MARK: - Property Wrapper To Make This All Work
@propertyWrapper
struct DistinctEnvironmentObject<Wrapped>: DynamicProperty where Wrapped : ObservableObject {
    var wrappedValue: Wrapped {
        _wrapped
    }

    @ObservedObject private var _wrapped: Wrapped

    init(_ keypath: KeyPath<EnvironmentValues, Wrapped>) {
        _wrapped = Environment<Wrapped>(keypath).wrappedValue
    }
}

// MARK: - Dependencies
class Microservice: ObservableObject {
    @Published private(set) var content: [String] = []

    func fetchContent() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            self.content = self.fakeContentForDemo
        }
    }

    private let fakeContentForDemo: [String]

    init(fakeContentForDemo: [String]) {
        self.fakeContentForDemo = fakeContentForDemo
    }
}

extension Microservice {
    static let posts = Microservice(
        fakeContentForDemo:  ["What about Mesa Verde?", "S'all good, man."]
    )
}

extension Microservice {
    static let users = Microservice(
        fakeContentForDemo: ["Jimmy", "Kim", "Mike"]
    )
}

extension Microservice {
    static let channels = Microservice(
        fakeContentForDemo: ["#watercooler", "#gifs", "#drugtrafficking"]
    )
}

// MARK: - Environment Boilerplate
struct PostsServiceKey: EnvironmentKey {
    static var defaultValue: Microservice {
        return Microservice.posts
    }
}

struct UsersServiceKey: EnvironmentKey {
    static var defaultValue: Microservice {
        return Microservice.users
    }
}

struct ChannelsServiceKey: EnvironmentKey {
    static var defaultValue: Microservice {
        return Microservice.channels
    }
}

extension EnvironmentValues {
    var posts: Microservice {
        get { return self[PostsServiceKey.self]  }
        set { self[PostsServiceKey.self] = newValue }
    }

    var users: Microservice {
        get { return self[UsersServiceKey.self]  }
        set { self[UsersServiceKey.self] = newValue }
    }

    var channels: Microservice {
        get { return self[ChannelsServiceKey.self]  }
        set { self[ChannelsServiceKey.self] = newValue }
    }
}

2      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.