How to preview UIViewController in Xcode Previews
Table of Contents
What is Xcode Preview
Apple introduces Xcode Previews in Xcode 11 with the coming of SwiftUI.
With Xcode Previews, you can see how SwiftUI views look in real-time, and you can interact with it without running your app.
This is far superior to Storyboard and Interface Builder we have in UIKit.
Here is an example of Xcode Previews.
As you can see, the update reflects on the preview once we add a new code.
And you can tap a button to change the view's state.
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
How to use Xcode Previews with UIViewController
You might not be aware that you can enjoy the benefit of Xcode Previews even though you are still using UIKit.
In this article, I will show you how to preview UIViewController using Xcode Previews.
To make your view controllers work with Xcode previews, you need to do three things.
- Import
SwiftUI
module. - Create a struct that conforms to the
PreviewProvider
protocol. - Wrap a view controller into a SwiftUI view using
UIViewControllerRepesentable
.
// 1
import SwiftUI
// 2
struct ViewControllerPreview: PreviewProvider {
// 3
static var previews: some View {
// return any UIViewControllerRepresentable here
}
}
1 Xcode preview works hand in hand with PreviewProvider
. It discovers preview providers and generates previews for us. PreviewProvider
is a part of the SwiftUI
module, so we need to import SwiftUI
to use it.
2 We create a struct that conforms to the PreviewProvider
.
3 Normally, we will return a SwiftUI view from the previews
static property. But we want to preview a view controller here, so we need to wrap it using the UIViewControllerRepresentable
protocol.
- Steps 1 and 2 are the same regardless of SwiftUI or UIKit.
- And we have learned step 3 in how to convert a view controller to SwiftUI.
So, we got everything ready. Let's jump to the implementation detail.
Using view controller from a Storyboard
As an example, I will try to use Xcode Preview with my existing view controller, which builds using a Storyboard.
UIViewControllerRepresentable
First, we need to convert a view controller into a SwiftUI view using UIViewControllerRepresentable
.
The process is straightforward. You just need to initialize your view controller and return it from makeUIViewController()
. You can read more about this in detail in how to convert a view controller to SwiftUI.
struct SwiftUIViewController: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> ViewController {
// 1
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard
let viewController = storyboard.instantiateInitialViewController() as? ViewController
else {
fatalError("Cannot load ViewController from Main storyboard.")
}
// 2
return viewController
}
func updateUIViewController(_ uiViewController: ViewController, context: Context) {}
}
1 We grab the storyboard that our view controller is sitting in and instantiate the view controller from that storyboard.
2 Then, we return that view controller from func makeUIViewController(context: Context) -> ViewController
.
Preview Provider
After converting a view controller to SwiftUI view, we are halfway done.
The only thing left is to use it for preview.
import SwiftUI
struct ViewControllerPreview: PreviewProvider {
static var previews: some View {
SwiftUIViewController()
}
}
Here is the result.
You can easily support sarunw.com by checking out this sponsor.
AI Grammar: Correct grammar, spell check, check punctuation, and parphrase.
Helpers
Having to create UIViewControllerRepresentable
for every view controller you want to preview is cumbersome.
If you have a lot of view controller classes, you should develop a helper method to easily wrap your view controller into UIViewControllerRepresentable
.
There are many ways to tackle this problem. I can give you one example here.
In this example, I will create a PreviewContainer
as a view controller wrapper.
import SwiftUI
import UIKit
// 1
struct PreviewContainer<T: UIViewController>: UIViewControllerRepresentable {
// 2
let viewController: T
// 3
init(_ viewControllerBuilder: @escaping () -> T) {
viewController = viewControllerBuilder()
}
// MARK: - UIViewControllerRepresentable
func makeUIViewController(context: Context) -> T {
// 4
return viewController
}
func updateUIViewController(_ uiViewController: T, context: Context) {}
}
1 I create a generic struct that can accept any type that is a subclass of UIViewController
. We make this struct conform to UIViewControllerRepresentable
since it will act as our SwiftUI view wrapper for our view controller.
2 We define an instance property that will hold a view controller.
3 We create an initializer that accepts a closure that returns a view controller. This will act as a view controller builder.
4 We return the resulting view controller from makeUIViewController()
.
This is how we use PreviewContainer
.
import UIKit
import SwiftUI
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
struct ViewController_Previews: PreviewProvider {
static var previews: some View {
PreviewContainer {
// 1
let storyboard = UIStoryboard(name: "Main", bundle: nil)
guard let viewController = storyboard.instantiateInitialViewController() as? ViewController
else {
fatalError("Cannot load ViewController from Main storyboard.")
}
return viewController
}
}
}
1 We provide a closure that returns a view controller as an argument for PreviewContainer
.
We can use this PreviewContainer
to preview any view controller without a need to recreate UIViewControllerRepresentable
.
Read more article about Xcode, Xcode Previews, or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareWhat's new in SF Symbols 5
In iOS 17, we can animate SF Symbols with the symbolEffect modifier.
Little big improvements in Xcode 15
Small improvements that make a big difference in day-to-day coding.