Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Custom Environment Values and Non-Sendable Errors

I have a following code. I use the Environment(.showMessage) in my SwiftUI view only to show and hide views. When I compile this code with Swift 6 I get the error (shown at the end).

struct ShowMessageAction {
    typealias Action = (String, MessageType) -> ()
    let action: Action
    func callAsFunction(_ message: String, _ messageType: MessageType = .error) {
        action(message, messageType)
    }
}

extension EnvironmentValues {
    @Entry var showMessage = ShowMessageAction { _, _ in }
}

    Static property 'defaultValue' is not concurrency-safe because non-'Sendable' type 'ShowMessageAction' may have shared mutable state. 

What can I do in this situation?

UPDATE 1:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I made the change but now MyProductListScreen is complaining.

      NavigationStack {
//Call to main actor-isolated initializer 'init()' in a synchronous // nonisolated context
                    MyProductListScreen()
                }

MyProductListScreen

    struct MyProductListScreen: View {
        
// It complains about showMessage. 
        @Environment(\.showMessage) private var showMessage
        @Environment(ProductStore.self) private var productStore
        @State private var isPresented: Bool = false
        @AppStorage("userId") private var userId: Int?

SOLUTION:

I ended up marking my destination property in AppScreen with @MainActor.

 @MainActor
    @ViewBuilder
    var destination: some View {
        switch self {
            case .home:
            NavigationStack {
                ProductListScreen()
            }
            case .myProducts:
            NavigationStack {
                MyProductListScreen()
                        .requiresAuthentication()
            }

>Solution :

This is very much related to how the @Entry macro generates the defaultValue property (See also my answer here).

@Entry in your current code generates

static let defaultValue = ShowMessageAction { _, _ in }

which is considered not safe because ShowMessageAction is not Sendable (See also SE-0412).

We would like defaultValue to be a computed property, so there is no global state. i.e.

static var defaultValue: ShowMessageAction { 
    ShowMessageAction { _, _ in } 
}

@Entry can generate this if you specify the type of the property explicitly.

@Entry var showMessage: ShowMessageAction = .init { _, _ in }

It is impossible for @Entry to generate a computed property without an explicit type, because a computed property needs an explicit type annotation, but macros cannot know the type of an arbitrary expression like ShowMessageAction { _, _ in }.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading