Optional result builder as a parameter

I'm having a hard time figuring out how to build a SwiftUI view that takes an optional @ViewBuilder. In my case, my app shows a bunch of lists with similar styling. Some of those lists represent paged data, and I trigger a load of the next page by appending an item at the end of the current list whose .onAppear() loads the next page.

My custom list view looks like this:

struct
ItemListView<Data, ID, Content, Trigger> : View
    where
        Data : RandomAccessCollection,
        Content : View,
        ID == Data.Element.ID,
        Data.Element : Identifiable,
        Trigger : View
        
{
    public  typealias   ContentBuilder      =   (Data.Element) -> Content
    public  typealias   TriggerBuidler      =   () -> Trigger
    
    public
    init(_ data: Data,
            @ViewBuilder content: @escaping ContentBuilder,
            @ViewBuilder trigger: @escaping TriggerBuidler?)   <--- error here
    {
        self.data = data
        self.content = content
        self.trigger = trigger
    }
}

Unfortunately, I get Result builder attribute 'ViewBuilder' can only be applied to a parameter of function type. This seems like an awfully restrictive requirement.

There are numerous questions of this nature online, but I can't seem to make any of them work for me in (I'm building with Xcode 13 and 12.5.1)

I tried making two init methods, one that didn't take the trigger parameter, but then it can't seem to figure out the Trigger generic parameter.

Suggestions much appreciated!

There are a few solutions. SwiftUI uses multiple initializers with the lesser initializers only available in extensions constrained to EmptyView. For example, Gauge has several, one like this:

init<V>(value: V, in bounds: ClosedRange<V> = 0...1, label: () -> Label) 
where CurrentValueLabel == EmptyView, 
      BoundsLabel == EmptyView, 
      MarkedValueLabels == EmptyView, 
      V : BinaryFloatingPoint

Instead of an optional closure you can also provide a default, such as @ViewBuilder trigger: @escaping TriggerBuilder = { EmptyView() }.

It also seems like result builders should be able support optional values in some way.

1 Like

Ah, I tried that, but perhaps I needed to constrain that initializer.

Terms of Service

Privacy Policy

Cookie Policy