Using Xcode Preview with your production code

Jun 4, 2019 23:40 · 3 minute read #Swift #SwiftUI #Xcode #Xcode Preview

Everyone is happy for SwiftUI, but real production code won’t be able to use it for a while. Not only SwiftUI is available starting iOS 13, but also many devices won’t be able to upgrade to iOS 13. Thus, if you cut iOS 12 from your minimum deployment target, you might lose a significant portion of your audience. So if you’re like me and you want (or need) to support lower iOS targets at least for the next year, you can still use Xcode Preview for prototyping.

Create new _App_Preview target and scheme

Important thing for me is to isolate my preview environment from the production one. To do that, I’m using a custom Target and a custom Scheme. I cloned my “production” target to save up some:

Create new preview target

Then I’ve added a new scheme for the new target.

Make your views/view controllers representable

SwiftUI brings two new protocols to bridge your views and view controllers to the declarative world: UIViewRepresentable and UIViewControllerRepresentable. I’m gonna use one of my Demo controllers, PostsViewController, to implement UIViewControllerRepresentable.

To do that I’m gonna create a new file, called PostsViewController+Preview.swift and make it available only to my DemoPreview target. This way I can easily separate preview code with production code:

#if DEBUG
import SwiftUI

extension PostsViewController: UIViewControllerRepresentable {

    typealias UIViewControllerType = PostsViewController

    func makeUIViewController(context: UIViewControllerRepresentableContext<UIViewControllerType>) -> UIViewControllerType {
        return PostsViewController()
    }

    func updateUIViewController(_ uiViewController: UIViewControllerType, context: UIViewControllerRepresentableContext<UIViewControllerType>) {
        // update the controller
    }
}


struct PostsViewController_Previews : PreviewProvider {
    static var previews: some View {
        PostsViewController()
    }

    static var platform: PreviewPlatform? = .iOS
}
#endif

Now, depending on the mood, Xcode should show you the Preview window! If it doesn’t happen, however, try to select any other file and then go back to the extension. And, if your project compiles, you should now see your view controller in the new Xcode Preview.

If it still doesn’t show you the view there is a pretty helpful message most of the time with explanation why (e.g. I had to switch to Swift 5 in this target to use it).

Prototyping

Sadly, the Preview window won’t show up on our main controller code (probably because we declared the preview in an extension). There is a trick for that as well. Add a new editor in your Xcode 11 (similar to adding Assistant Editor in Xcode 10). Now on one side you can open the controller (for me it would be PostsViewController) and on the other the extension with a preview (PostsViewController+Preview). Now just update the height of the extension editor + preview.

Here is how it looks and works for my small demo project:

[Edit] Better prototyping

As this post came out faster than most of the sessions of SwiftUI, it turns out that there is an easier way for prototyping with extensions. When you go to the extension, tap on the “pin” button in the Xcode Preview at the bottom-left of the canvas (turns blue when you pin your view). Now the view is pinned and you can easily edit the main controller while the preview will still show on the assistant canvas.

Current Caveats

Even with all these problems it’s still better (at least for me) than Playgrounds. And if the problems with crashes will be resolved, it should be a great tool for prototyping in the future.



share:

Comments