GO FURTHER, FASTER: Try the Swift Career Accelerator today! >>

SOLVED: #Preview macros with @Binding<String>

Forums > SwiftUI

@keyle  

Hello,

the new XCode 15 comes with macros, and a prominent one is the #Preview {}

However, in the past, I could do this

struct NetworkButton_Preview: PreviewProvider {
    static var previews: some View {
        @State var b:String = "Success test"
        @State var c:String = "Nope test"
        VStack{
            NetworkButton(selectedTab: $b)
            NetworkButton(selectedTab: $c)
        }
    }
}

where selectedTab is @Binding var selectedTab: String

But the same with the new syntax, will not work.

#Preview {
    @State var b:String = "Success test"
    @State var c:String = "Nope test"
    VStack{
        NetworkButton(selectedTab: $b)
        NetworkButton(selectedTab: $c)
    }
}

I've looked through the WWDC video on it but couldn't find the answer. For now, I've reverted to using the old syntax pre-macros.

Is there a way?

3      

Not sure if this will work for your use case ?

#Preview {
  @State var toggleA = false
  @State var toggleB = true
    return VStack {
        Toggle("A", isOn: $toggleA)
        Toggle("B", isOn: $toggleB)
    }
}

3      

@keyle  

No, no that's not it. That won't compile.

Cannot use explicit 'return' statement in the body of result builder 'ViewBuilder'

3      

The body of a #Preview has to be a ViewBuilder, so you can't do what you are trying to do. You would need a View to go in there instead.

@freestanding(declaration)
macro Preview(
    _ name: String? = nil,
    traits: PreviewTrait<Preview.ViewTraits>...,
    @ViewBuilder body: @escaping () -> any View
) -> ()

So something like this:

struct NetworkButtonStack: View {
    @State var b:String = "Success test"
    @State var c:String = "Nope test"

    var body: some View {
        VStack{
            NetworkButton(selectedTab: $b)
            NetworkButton(selectedTab: $c)
        }
    }
}

#Preview {
    NetworkButtonStack()
}

3      

The solution to this is you need to return your VStack from the trailing closure.

#Preview {
    @State var b:String = "Success test"
    @State var c:String = "Nope test"
    return VStack{
        NetworkButton(selectedTab: $b)
        NetworkButton(selectedTab: $c)
    }
}

The body of the #Preview is a closure that returns a View. So given how closures work by adding the State variables you can no longer us the shorthand implicit return. You must explicitly return the view.

@freestanding(declaration)
macro Preview(
    _ name: String? = nil,
    body: @escaping @MainActor () -> View
)

https://developer.apple.com/documentation/swiftui/preview(_:body:)/

3      

Using the Previewable() macro is a simpler way than the currently accepted answer.

#Preview {
    @Previewable @State var b: String = "Success test"
    @Previewable @State var c: String = "Nope test"
    VStack{
        NetworkButton(selectedTab: $b)
        NetworkButton(selectedTab: $c)
    }
}

Source: https://developer.apple.com/documentation/SwiftUI/Previewable()

1      

I am using #Preview, and I had a return of a view, and then I updated a class that is passed in to the view, and I started getting the error Cannot use explicit 'return' statement in the body of result builder 'ViewBuilder'. But I didn't change anything in the preview block itself!!!

   

Hacking with Swift is sponsored by Alex.

SPONSORED Alex is the iOS & Mac developer’s ultimate AI assistant. It integrates with Xcode, offering a best-in-class Swift coding agent. Generate modern SwiftUI from images. Fast-apply suggestions from Claude 3.5 Sonnet, o3-mini, and DeepSeek R1. Autofix Swift 6 errors and warnings. And so much more. Start your 7-day free trial today!

Try for free!

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.