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:
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 }.