1

I am using the modifier sheet(item:onDismiss:content:) to show a sheet, where the content of the sheet depends on the item that is passed as parameter. The body of the sheet is built using a function which is passed the item as parameter.

Here is a simplified example:

struct ContentView: View {
    @State private var sheetContent: SheetContent?

    var body: some View {
        HStack(spacing: 30) {
            Button("Foo") { sheetContent = .foo }
            Button("Bar") { sheetContent = .bar }
        }
        .buttonStyle(.bordered)
        .sheet(item: $sheetContent, content: sheetBody) // 👈 issue here
    }

    private func sheetBody(contentType: SheetContent) -> some View {
        Text("\(contentType)".capitalized)
            .font(.largeTitle)
            .foregroundStyle(.white)
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(contentType == .foo ? .yellow : .orange)
            .onTapGesture { sheetContent = nil }
    }
}

enum SheetContent: Identifiable {
    case foo
    case bar

    var id: SheetContent { self }
}

Up until Xcode 26.0 beta 3, this compiled without warnings, even when using Swift 6 with strict concurrency checking. With the beta 3 version and Swift 6, it now shows the following warning against the .sheet modifier:

Screenshot

⚠️ Cannot convert '@MainActor @Sendable (SheetContent) -> some View' to '@MainActor (SheetContent) -> some View' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol; this will be an error in a future Swift language mode

❕Type 'some View' does not conform to 'Sendable' protocol

One workaround is to use a closure to call the function sheetBody, instead of trying to pass the function as a parameter:

.sheet(item: $sheetContent) { item in
    sheetBody(contentType: item)
}

However, I am wondering if this workaround can be avoided by adding annotations to the function in some way? I tried adding @Sendable, but this also requires making it async, which no longer satisfies the signature of the sheet modifier.

How can the function be passed as parameter to the .sheet modifier without Xcode 26.0 beta 3 reporting a warning?


UPDATE The warnings are no longer shown with Xcode beta 5. So no workaround necessary.

0

2 Answers 2

1

Notice that the warning message is incorrect in the first place. The content closure for sheet is not required to be main actor isolated.

If you write a function with exactly the same signature, but with a different name, you can call that function without any warnings.

// this has no warnings
public extension View {
    nonisolated
    func sheet2<Item, Content>(
        item: Binding<Item?>,
        onDismiss: (() -> Void)? = nil,
        @ViewBuilder content: @escaping (Item) -> Content
    ) -> some View where Item : Identifiable, Content : View {
        sheet(item: item, onDismiss: onDismiss, content: content)
    }
}
// this also has no warnings
.sheet2(item: $sheetContent, content: sheetBody)

However, as soon as you move sheet2 to a separate framework that is compiled with Swift 5 mode, the warning appears again.


Another way to remove the warning is simply cast:

.sheet(item: $sheetContent, content: sheetBody as ((SheetContent) -> _))

Changing the cast to @MainActor (SheetContent) -> _ would cause the warning again.


I also reproduced a similar but slightly different warning message using this code:

@MainActor
func h() -> NonSendable {
    NonSendable()
}

func f(_ x: @MainActor () -> NonSendable) {}

func g() {
    f(h)
}

class NonSendable {
    var x = 1
}

Cannot convert '@_Concurrency.MainActor @Sendable () -> Foo.NonSendable' to '@_Concurrency.MainActor @Sendable () -> Foo.NonSendable' because crossing of an isolation boundary requires parameter and result types to conform to 'Sendable' protocol; this will be an error in a future Swift language mode

This is literally reporting a warning about converting from one type to itself. The warning goes away if h is nonisolated.


Based on these observations, I think this is probably just a regression bug, and you don't need to worry about it. There are recently many new function type conversions that are added, due to the introduction of nonisolated(nonsending) and @concurrent function types (See SE-0461). It's not unexpected that this kind of regression happens.

Sign up to request clarification or add additional context in comments.

1 Comment

The warnings are no longer shown with Xcode beta 5. So I think you were probably correct in concluding the problem was a regression bug.
1

As @Sweeper mentioned, depending on what your are doing within sheetBody, you could:

  1. Make the function nonisolated:
struct ContentView: View {

    var body: some View {
        ...
        .sheet(item: $sheetContent, content: sheetBody)  // 👈 issue here
    }

    nonisolated  // ✅ fix here
    private func sheetBody(contentType: SheetContent) -> some View {
        ...
    }
}

2. Just cast the function to make the compiler happy:

struct ContentView: View {

    var body: some View {
        ...
        .sheet(item: $sheetContent, content: sheetBody as ((SheetContent) -> _))  // ✅ fix here
    }
}

1 Comment

Thanks for your suggestions. Unfortunately, solution 1 doesn't work in my real-life case and actually it doesn't work in the example here either, it gives an error for the closure passed to .onTapGesture (perhaps because I have strict concurrency checking turned on). But solution 2 does indeed eliminate the warning. I'm hoping that Sweeper is right with his assessment that this is a regression bug. If so, it should disappear in a new version. However, it still exists in beta 4.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.