Eugene Belinski profile pictureEugene Belinski

he / him

5 practical tips for adopting SwiftUI in existing iOS apps

SwiftUI is the exciting new UI framework for developing native apps for iPhone and other Apple platforms, but bringing it to existing UIKit applications presents its own set of challenges. If you’re an iOS developer, you are hopefully by now familiar with UIHostingController, and are looking for more practical tips on how to adopt SwiftUI in your existing project.

1. Set your app to support iOS 14 and up

SwiftUI was announced at WWDC 2019, and supports iOS 13 and up. If you want to support as many users as possible while using SwiftUI, you might be tempted to support iOS 13. However, the feature set that shipped with the original version of SwiftUI is considered to be very limited. By supporting iOS 13, you’ll miss out on any newer features that were introduced in WWDC 2020 for iOS 14.

New SwiftUI features introduced in iOS 14 include ProgressView, LazyVStack and LazyHStack, a new toolbar API, and much more.

2. Don’t be afraid to use new features, even if they’re not supported on iOS 14

At WWDC 2021, Apple added even more features in SwiftUI for iOS 15. As with last year, newly introduced features may generally be used on devices running iOS 15. However, this doesn’t necessarily mean you can’t use a new iOS 15 feature on an app that supports iOS 14 or even lower, as long as you implement a backup implementation for older versions of iOS.

A good example of this is AsyncImage. This new SwiftUI view makes it dead simple to display an image from anywhere on the internet onto a SwiftUI screen. However, it only supports iOS 15, so an alternative implementation is needed.

When I faced this issue a few weeks ago, I decided to add URLImage to my project and use it for iOS 14 and below. Although I typically try to avoid third-party dependencies in my iOS projects whenever possible, I decided that this would be a justifiable exception because of the temporary nature of the situation. In other words, I figured I would almost certainly be able to remove it from my project in a year’s time when I drop support for iOS 14.

My implementation was thus:

if #available(iOS 15.0, *) {
    AsyncImage(url: fullImageURL) { image in
            .aspectRatio(contentMode: .fit)
} else {
    URLImage(url: url) { image in
            .aspectRatio(contentMode: .fit)

3. Use Model-View-ViewModel (MVVM)

…Or at least some clear pattern.

UIKit development lends itself naturally to the Model-View-Controller (MVC) architectural pattern. Any class that subclasses UIView is a View, and any class that subclasses UIViewController is a Controller. Then Model classes come naturally.

SwiftUI development lends itself naturally to… Model-View? Wait, that can’t be right. Where does our Controller logic go? In SwiftUI, there are no Controllers to update the views, because the SwiftUI framework updates the views for us, based on the instructions we feed into a view telling SwiftUI how it should look for different states.

class Employee {
    let name: String

4. Give up on UI testing

I wish I was wrong on this one, but for now, UI testing SwiftUI apps is not really worth it.

5. Spend money on good resources

The iOS development ecosystem is known for having incomplete official documentation, but rich documentation and resources provided by third-party websites and developers. Some of the best resources though aren’t free.