I am trying to use an enum across multiple modules as follows
// ComponentsModule
public struct FloatView: View {
var str: String
public init(str: String) {
self.str = str
}
public var body: some View {
Text("I am A float displaying: \(str)")
}
}
// PopupModule
import ComponentsModule
import SubscriptionModule // circular dependency !!!
public enum PopupItem: View {
case float(String)
case sheet(SubscriptionType) // need to import SubscriptionModule to gain access to SubscriptionType
public var body: some View {
switch self {
case .float(let string):
FloatView(str: string)
case .sheet(let subscriptionType):
SubscriptionView(subscriptionType: subscriptionType) // need to import SubscriptionModule to gain access to SubscriptionView
}
}
}
// SubscriptionModule
// SubscriptionType, SubscriptionView, SubscriptionViewViewModel and SubscriptionService live inside Subscription Module
import PopupModule // // circular dependency !!!
public struct SubscriptionType {
var name: String
}
public struct SubscriptionView: View {
@StateObject private var vm = SubscriptionViewViewModel()
var subscriptionType: SubscriptionType
public init(subscriptionType: SubscriptionType) {
self.subscriptionType = subscriptionType
}
public var body: some View {
Text("Your Subscription type is: \(subscriptionType.name)")
}
}
public final class SubscriptionViewViewModel: ObservableObject {
private var subscriptionService: SubscriptionServiceProtocol
public init(
subscriptionService: SubscriptionServiceProtocol = SubscriptionService()
) {
self.subscriptionService = subscriptionService
}
private func loadSubscriptionType() {
let subscriptionType = subscriptionService.getSubscriptionType()
let popupItem: PopupItem = .sheet(subscriptionType) // need to import PopupModule to gain access to PopupItem
NotificationCenter.default.post(name: Notification.Name("subscriptionType"), object: popupItem) // PopupItem used elsewhere in the code via an observer }
}
public protocol SubscriptionServiceProtocol {
func getSubscriptionType() -> SubscriptionType
}
public final class SubscriptionService: SubscriptionServiceProtocol {
public init() {}
public func getSubscriptionType() -> SubscriptionType {
SubscriptionType(name: "Cold")
}
}
How do I employ SOLID principles, Dependency Injection, Composition Root, sharing Views across multiple modules or any other architectural or design principals to completely decouple the modules and achieve this design without running into issues like circular dependency etc. The SubscriptionViewViewModel is initialized in main App and shared accross the app via EnvironmentObject
Thought i would create in an AbstractionModule a protocol
public protocol PopupItemProtocol {
case float(String)
case sheet(SubscriptionType)
}
and witness it with PopupItem, then use
PopupItemProtocol.float("Some text")
in a module that imports only the AbstractionModule, but turns out i need the conforming type i.e PopupItem, so dead end there.