Possible? Use compiler synthesized init to initialize @ViewBuilder var in a SwiftUI View?

So I wanted to avoid hand write init for this:

struct SimpleView<Content: View>: View {
    
    //
    // too many properties here, prefer to use compiler synthesized init...
    //
    
    // but how to deal with this? Marking this @ViewBuilder result in compile error:
    // Error: Function builder attribute 'ViewBuilder' can only be applied to a property if it defines a getter
    // @ViewBuilder
    let content: () -> Content
    
    // Is there anyway to skip writing this and use the compiler synthesisize init for content?
    init(@ViewBuilder content: @escaping () -> Content) {
        //
        // here would be lots of boiler plate properties init to write
        //
        self.content = content
    }
    
    var body: some View {
        content()
    }
}

I don't think there's anyway around it. As is, you'd need to write it out.

PS

I think most other views, such as Button uses non-escaping version. So I'd suggest that you follow suits. In which case you'd need to invoke the call within init and save the data.

1 Like

Oh :astonished: I didn't get the memo. All the examples I see all do non-escape...I thought they were just oversight. Wonder what different does this make? Calling it in init vs. in body...hmmm :thinking:

Either way, can't use compiler synthesized init then...seem if there is @autoclosure, seem there should be something like the inverse of it.

Well, one could always pitch some...

Regarding the difference, there isn't much if you use it once. If you use it a few times, the compiler may have hard time proving that the function is pure (which I believe it would be for your usage). So it has no choice but to actually call it a few times. Storing a closure can also lead to some reference cycle shenanigan if you're not careful. Though to be fair, it could happen to any type that capture references.

Do you mean they all do escape?

No, they all do as you said, non-escape. I thought doing @escaping is better, guess not :star_struck:

With all that said, it's not that escape == bad, non-escape == good. If the function is sensitive to when you call it, you may want to escape it to call later.

Non-escaping closure is more appropriate here because you expect that the function is pure and side-effect free, whether you call it now or later, the result is the same. You also reduce the risk of reference cycle I mentioned earlier. One downside is that, instead of storing a closure (and captured variable), you store Content which can be potentially large.

2 Likes

This is possible now in Swift 5.4

Terms of Service

Privacy Policy

Cookie Policy