Swift protocol and a method returning "some View"

Viewed 2622

So a protocol doesn't support some View as a return type... I'm trying this:

public extension View {
    func popSheet(isPresented: Binding<Bool>, arrowEdge: Edge = .bottom, content: @escaping () -> PopSheet) -> some View {
        Group {
            if UIDevice.current.userInterfaceIdiom == .pad {
                popover(isPresented: isPresented, attachmentAnchor: .rect(.bounds), arrowEdge: arrowEdge, content: {
                    content().popover()
                })
            } else {
                actionSheet(isPresented: isPresented, content: {
                    content().actionSheet()
                })
            }
        }
    }
}

protocol PopSheet {
    func actionSheet() -> ActionSheet
    associatedtype View
    func popover() -> View
}

But the whole function declaration fails and the content().popover() errors as well.

Method must be declared internal because its parameter uses an internal type

Protocol 'PopSheet' can only be used as a generic constraint because it has Self or associated type requirements

Member 'popover' cannot be used on value of protocol type 'PopSheet'; use a generic constraint instead

2 Answers

There's nothing fundamentally wrong here. Just several small mistakes.

First, your View associatedtype has nothing to do with SwiftUI.View. It just happens to have the same name. What you likely meant was this:

public protocol PopSheet {
    associatedtype V: View   // Create a new type that conforms to View
    func actionSheet() -> ActionSheet
    func popover() -> V
}

Your second problem is that you can't rely on PopSheet directly, since it has an associatedtype. You mean that you expect some concrete type that conforms to PopSheet:

func popSheet<Sheet: PopSheet>(isPresented: Binding<Bool>, 
                               arrowEdge: Edge = .bottom, 
                               content: @escaping () -> Sheet) -> some View {

With that, your implementation should be fine.

For the use a generic constraint instead issue, the reason is:

...

That’s something that happens when we try to reference a generic protocol directly — that is, a protocol that has either associated types, or requires the conforming type (which Self refers to) to be known. For example, the built-in Equatable protocol uses Self within its declaration

...

You can find detailed explanation in this great blog post.

Great day, and Happy coding!

Related