hmlongco / Factory

A new approach to Container-Based Dependency Injection for Swift and SwiftUI.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

@MainActor issue when using @InjectedObject

mreaybeaton opened this issue · comments

Hi,

I have just started using Factory and one issue I am currently facing is where the InjectedObject is stated as MainActor

Converting function value of type '@MainActor (FirstScreenRoutes) -> some View' to '(FirstScreenRoutes) -> some View' loses global actor 'MainActor'

struct FirstScreenCoordinator<Content: View>: View {
    @InjectedObject(\.appFlowState) var state: AppFlowState
    @ViewBuilder var content: () -> Content
    
    var body: some View {
        NavigationStack(path: self.$state.path) {
            content().navigationDestination(for: FirstScreenRoutes.self, destination: self.route)
        }
    }
    
    @ViewBuilder private func route(to route: FirstScreenRoutes) -> some View {
        switch route {
        case .second:
            secondDestination()
        }
    }
    
    private func secondDestination() -> some View {
        return Text("Second Screen")
    }
}

If I change Injected to StateObject for example the error goes away.

Looking at the code for InjectedObject

    /// Manages the wrapped dependency.
    @MainActor public var wrappedValue: T {
        get { dependency }
    }
    /// Manages the wrapped dependency.
    @MainActor public var projectedValue: ObservedObject<T>.Wrapper {
        return $dependency
    }

What is the purpose of the MainActor? does it need to be there?

There's not enough code here to diagnose this.

Does this help, full project. Warning is in FirstScreenCooridinator
https://github.com/mickeysox/TestCoordinator10.git

We also have the same problem in the entire project with this issue. After migrating from Resolver to Factory the project build fail because of isolation problems.

To solve it we have to use such pattern
@ObservedObject private var property = Container.shared.property()

The Problem occurs when we creates subviews in @ViewBuilder-fuctions with views having @InjectedObject inside and if this object is using outside of the body-property. Only the body-property is running on main actor.

Try the develop branch. I removed the @mainactor attributes from InjectedObject as a test. Note you need to remove the @mainactor attributes from your view vars as well to clear the error.

struct FirstScreenCoordinator<Content: View>: View {
    
    @InjectedObject(\.appFlowState) var state: AppFlowState

    @ViewBuilder var content: () -> Content
    
    var body: some View {
        NavigationStack(path: self.$state.path) {
            content().navigationDestination(for: FirstScreenRoutes.self, destination: self.route(to:))
        }
    }
    
     /* @MainActor */ @ViewBuilder private func route(to route: FirstScreenRoutes) -> some View {
        switch route {
        case .second:
            secondDestination()
        }
    }
    
    /* @MainActor */ private func secondDestination() -> some View {
        return Text("Second Screen")
    }
}