TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

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      

Hacking with Swift is sponsored by Blaze.

SPONSORED Still waiting on your CI build? Speed it up ~3x with Blaze - change one line, pay less, keep your existing GitHub workflows. First 25 HWS readers to use code HACKING at checkout get 50% off the first year. Try it now for free!

Reserve your spot now

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.