Give your simulator superpowers

RocketSim: An Essential Developer Tool
as recommended by Apple

#Preview SwiftUI Views using Macros

Starting with Xcode 15 and Swift 5.9, you can create previews for your SwiftUI view using the new #preview Macro. The macro replaces the PreviewProvider protocol that required us to define previews within a static computed property.

Swift 5.9 also introduced Macros, the concept behind this new hashtag attribute. I encourage you to read Swift Macros: Extend Swift with New Kinds of Expressions to understand the concepts before diving deeper into this new way of previewing SwiftUI views.

Creating a SwiftUI #Preview

Creating a preview for one of your SwiftUI views can be done as follows:

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello World!")
        }
    }
}

#Preview {
    ContentView()
}

Previously, we would’ve written the same preview configuration as follows:

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

The Macro simplifies the definition of previews and makes it easy to provide titles for your previews:

#Preview("Hello World!") {
    ContentView()
}

Defining multiple previews is as easy as defining multiple macro definitions. For example, to create multiple configurations of an article view:

Use a #Preview macro for each view you want to preview.

How do you stay current as a Swift developer?

Let me do the hard work and join 19,138 developers that stay up to date using my weekly newsletter:

Previewing UIKit and AppKit

Unlike the PreviewProvider protocol, the #Preview macro lets you create previews for UIKit and AppKit views. This is incredibly valuable for older projects that couldn’t benefit from SwiftUI back in the day.

Imagine having a similar article view as before, but defined in UIKit:

import UIKit

final class ArticleViewController: UIViewController {

    var titleLabel: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = UIFont.preferredFont(forTextStyle: .title1)
        return label
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(titleLabel)
        NSLayoutConstraint.activate([
            titleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            titleLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor)
        ])
    }
}

We can now create a preview using the macro as follows:

#Preview {
    let articleViewController = ArticleViewController(nibName: nil, bundle: nil)
    articleViewController.titleLabel.text = "Previews for UIKit work!"
    return articleViewController
}

And Xcode will show you a preview accordingly:

You can use the #Preview macro with UIKit and AppKit views.

Can I use #Preview on iOS 16 and below?

While the new way of creating previews works great on iOS 17 and up, you’ll notice it doesn’t work when your project targets lower versions:

‘Preview’ is only available in iOS 17.0 or newer

We can confirm this behavior by right-clicking the #Preview macro and selecting “Expand Macro.” Xcode will show the code generated by the Macro:

Expanding the Macro shows it’s only available on iOS 17 and up.

These compiler errors show up even if you select the iOS 17 Simulator. You could argue that you’ll only preview views using iOS 17, but your project won’t even build for running on iOS 16 and below.

While I’ve looked into compiler directives to work around this issue, it seems impossible in the current Xcode 15 beta versions to use previews within projects targeting iOS 16 or below. During WWDC 23, the development team replied to this issue in Slack:

Yes, both of those cases with backwards deployment are known issues with the #Preview macro at this time.

In other words, let’s hope for a future fix that allows us to use the #Preview macro in projects targeting older OS versions.

Conclusion

The new #Preview macro simplifies how we define previews for our SwiftUI views. The macro also allows defining previews for UIKit and AppKit views, which can significantly benefit older app projects.

If you like to improve your Xcode knowledge, even more, check out the Xcode category page. Feel free to contact me or tweet me on Twitter if you have any additional tips or feedback.

Thanks!

 
Antoine van der Lee

Written by

Antoine van der Lee

iOS Developer since 2010, former Staff iOS Engineer at WeTransfer and currently full-time Indie Developer & Founder at SwiftLee. Writing a new blog post every week related to Swift, iOS and Xcode. Regular speaker and workshop host.

Are you ready to

Turn your side projects into independence?

Learn my proven steps to transform your passion into profit.