WWDC24 SALE: Save 50% on all my Swift books and bundles! >>

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      

Save 50% in my WWDC sale.

SAVE 50% To celebrate WWDC24, all our books and bundles are half price, so you can take your Swift knowledge further without spending big! Get the Swift Power Pack to build your iOS career faster, get the Swift Platform Pack to builds apps for macOS, watchOS, and beyond, or get the Swift Plus Pack to learn advanced design patterns, testing skills, and more.

Save 50% on all our books and bundles!

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.