EnvironmentObject in protocol of SwiftUI View

Viewed 1311

I want to make protocol like this :

protocol SubscriptionManagerView: View {
    var subscriptionManager: EnvironmentObject<SubscriptionManager> { get set }
}

To use in view like this for exemple :

struct Shop: View, SubscriptionManager {
    @EnvironmentObject var subscriptionManager: SubscriptionManager

First problem is that property wrapper @EnvironmentObject can't make me respond to protocol SubscriptionManagerView.

Finally I want to use for a custom modifier like this :

extension View where Self : SubscriptionManagerView {
    func subscriptionManagerAlert() -> some View {
        self.alert(isPresented: self.$subscriptionManager.stateShowAlert) {
            Alert(title: Text(self.subscriptionManager.transactionStateTitle)
                ...
                  }))
        }
    }
}

Any idea to work in this way ?

1 Answers

Here is a demo of possible approach - the idea is to use view modifier with explicitly injected subscription manager, so contract of interface guaranties that client view of modifier will provide us required object.

Tested with Xcode 12 / iOS 14.

class SubscriptionManager: ObservableObject {
    @Published var stateShowAlert: Bool = false
    @Published var transactionStateTitle = "Test"
}

struct SubscriptionManagerModifier: ViewModifier {
    @ObservedObject var subscriptionManager: SubscriptionManager
    func body(content: Content) -> some View {
        content
            .alert(isPresented: self.$subscriptionManager.stateShowAlert) {
                Alert(title: Text(self.subscriptionManager.transactionStateTitle))
            }
    }
}

extension View {
    func subscriptionManagerAlert(with subscriptionManager: SubscriptionManager) -> some View {
        self.modifier(SubscriptionManagerModifier(subscriptionManager: subscriptionManager))
    }
}

struct Shop: View {
    
    @EnvironmentObject var subscriptionManager: SubscriptionManager
    
    var body: some View {
        Button("Test") {
            subscriptionManager.stateShowAlert.toggle()
        }
        .subscriptionManagerAlert(with: subscriptionManager)
    }
}

struct Shop_Previews: PreviewProvider {
    static var previews: some View {
        Shop().environmentObject(SubscriptionManager())
    }
}

Related