In 2019, Apple shook up it’s development eco-system with the introduction of SwiftUI, a totally new UI framework for creating apps on all of it’s platforms. The excitement for this new toolset within the developer community was palpable to say the least, and many of us began tinkering with it immediately.
As with all brand new platforms, there were lots of rough edges, bugs, and other issues that made it pretty unrealistic to use SwiftUI in a production app. If nothing else, the fact that it could only run on iOS 13 was a show-stopper for most people.
Fast-forward one year, and Apple has now shipped it’s annual platform updates, with many improvements to SwiftUI among other things. The framework is more stable, feature-rich, and stable than it was in year #1. And, with Apple’s shift towards universal apps, it is now the preferred method for write-once, run on any Apple platform.
But is it time for you to dive in and start migrating your apps today? The short answer is: maybe. I’ll spend the rest of this post exploring that question further, tapping into my own experience building and shipping a SwiftUI-first app. Whether you’re a developer trying to determine if it’s time to spend the time ramping up, or a Founder/CTO/VP trying to decide if this SwiftUI thing all of your developers have been clamoring about lately is worth the time investment, you should have a much better understanding of the state of the platform by the end of the post.
Because I’m an eternal optimist, let’s start with the good.
Reasons to migrate to SwiftUI
Drastically improved design/development workflow
If you’ve done both front-end web and mobile development you know that the code-build-run cycle for web is blindingly fast compared to mobile. On web, you tweak your HTML/CSS/JS and just refresh the browser to see your changes. It makes reproducing a design extremely fast and iterative, and when it comes time to make tweaks with the aid of a designer sitting next to you, it’s also very ideal.
Contrast that with traditional mobile development, where you make changes in a mostly unruly layout system, wait for the app to recompile, then deploy to either a device or simulator and run the app. Every mobile developer knows how agonizing this process is after having to repeat it hundreds if not thousands of times a day.
SwiftUI has largely eliminated this problem with Xcode’s new ability to provide a live preview alongside your code. Open up any SwiftUI view class, and you’ll be greeted with a panel that runs and constantly updates a preview screen you configured as part of your view.
This cuts the development cycle time by an order of magnitude. You can tweak and nudge positioning, fonts, colors, and even layout structure, then see the changes in effect almost instantly. What’s more, you can easily configure your preview provider to run the view on any device screen, making it very simple to determine how your view will look, regardless of screen dimensions.
If live preview was the only thing included with the price of admission, SwiftUI would probably be worth it, just in terms of the time it saves during development.
Superior layout system
The layout system is something every front-end developer needs to understand thoroughly. It is the backbone of every screen, and how easy it is to use will have a very direct impact on how efficient developers can be at realizing a design.
Thankfully, SwiftUI does not disappoint. Rather than relying on a system of anchors and constraints like UIKit’s auto-layout system, it is based on a more conventional grid-style system. Views are nested in a declarative hierarchy and expand/contract based on various configuration options. There are very few top-level layout constructs that are extremely flexible, but also very approachable.
SwiftUI layouts also fully adopt Apple’s new philosophy of universal apps. Common containers and controls render and behave based on the runtime so your UI feels at home on any Apple platform, with very little effort from you.
NavigationView for example, renders a single screen navigation stack when running on smaller screens like iPhone, but run that same code on an iPad or Mac, and you’ll automatically get a dual-panel split view.
Finally, all layout in SwiftUI is defined directly in code. Gone are the days of defining layout in Interface Builder and dealing with unmaintainable XIB or Storyboard files that are impossible to work on with more than one person. Code is more concise, easy to reason about, and trackable/diffable through version control. All around a much better situation that makes it faster and less error-prone to write solid, maintainable layouts.
State-based and reactive by default
Another core tenant of SwiftUI is the idea of built-in state management that is reactive-first. Every SwiftUI view is bound to a series of state objects via one of several built-in mechanisms. When any attributes of a given state object change, the system intelligently re-renders any part of the view that needs to reflect those changes. In this way, you end up defining your views as a function of your application’s state at any given time.
The approach is functional in nature and contrast greatly to the imperative approach found previously when using UIKit/AppKit. By inherently binding views to state, an entire class of glue code is no longer needed, and a whole heap of bugs are no longer possible.
The approach is definitely something developers need to get used to, it requires a different way of thinking than before. But, once mastered, this new system is objectively superior, if for no other reason, than for the reduction in the amount of code required to render a given screen. Less code means easier maintenance, and less likelihood of bugs. And when the platform itself includes all the tools required to achieve a given architecture, all the better.
As it did with the rollout of Swift, Apple wisely surmised that very few developers would be able to fully adopt SwiftUI early on. For that reason, it made it possible to embed SwiftUI views inside UIKit apps, and vice versa, to wrap UIKit components in SwiftUI views. This means that if you want to dip your feet in the SwiftUI water before diving in entirely, you can do so for single screens, or even specific sections of a screen. Its a great way to start learning the framework while primarily remaining in the comfort of UIkit/AppKit.
Reasons to avoid SwiftUI (for now)
Somewhat steep learning curve
As with any great framework, SwiftUI is easy to get started with, but takes considerable time to master. Much like the transition from Objective-C to Swift, if you are considering migrating a project to SwiftUI or starting a new SwiftUI project with developers that are unfamiliar with the framework, you must build in ramp up time into your project plan. My first SwiftUI app probably would’ve taken less time to build in UIKit, as I was learning each step of the way through. However, now that I’ve experienced all the common stumbling blocks, I can honestly say I can accomplish most things faster via SwiftUI and much prefer it even at this relatively early stage.
Many common components are still unavailable
When you try to replace frameworks that are as mature and broad as UIKit and AppKit, it is impossible to get it all done in one pass. Apple definitely took an incremental approach with SwiftUI, enabling the most common use-cases first, and making it fairly painless to bridge to UIKit/AppKit when necessary.
Still, it can be time-consuming to have to continuously bridge components that just worked out of the box previously.
SFSafariViewController are just a few of the UIKit components that currently have no SwiftUI equivalent. The good thing is that there’s enough SwiftUI adoption at this point that the community has stepped up in a huge way and it is fairy easy to find open source SwiftUI implementations of these an other missing components.
In some cases, SwiftUI includes components that are missing key features of their UIKit equivalents. For example, it’s version of
UITextField has no control over the keyboard “return” key, so creating a form with tight keyboard navigation is not possible without bridging the UIKit component. When you encounter a component that is 90% fully-featured, but something you really need is in that 10% delta, having to wrap the UIKit analog is painful.
The framework is still evolving
SwiftUI is only two years old at the time of writing. Stop and think how much Swift itself has changed since the 2 year mark, and you’ll have a good idea why the relative immaturity of the framework can be a liability. The delta between the first and second year of SwiftUI was not massive, but there are no guarantees around what may change or be removed as the framework matures. This rate of change will ultimately slow down for sure, but at this point, it’s still worth noting that you may have the ground shift beneath your feet and you should count for that risk / required effort.
Minimum SDK is iOS 13
One of the hardest pills to swallow around SwiftUI was the requirement that apps using it needed to set minimum supported iOS version to iOS 13. For many established apps, it’s pretty standard to support at least the previous year’s iOS version and some maintain support even further back. While iOS does have a very high update rate compared to Android, this fact was and still is a deal-breaker for some apps. As with framework maturity, this problem will slowly dissipate as time goes on and subsequent versions of iOS are released.
So should you embrace the future and go whole hog on SwiftUI right now? As I said in the title of this post, it’s complicated. If your organization supports a very mature app with tons of users and an established product roadmap, it would be pretty risky and time consuming to migrate everything to SwiftUI right now. In addition, unlike the Objective-C to Swift transition, adopting SwiftUI fully means that some things maybe extremely difficult or impossible to reproduce in your UI, so you need to be OK with the possibility of making some minimal concessions until the framework further matures. The best path forward for teams in this situation is to start adopting SwiftUI on a screen-by-screen basis using the bridging mechanisms on offer. In this way you can slowly migrate fully over time, as the framework evolves and becomes more feature complete.
With that said, if you’re just spinning up a new app/company, it’s pretty clear that SwiftUI is Apple’s vision for how UI will be developed for the next decade, so it probably would behoove you to get on board now. Every new screen created using UIKit today is going to be technical debt that you’ll have to eventually pay down. Aside from that fact, once you master the framework, you’ll start to move much faster, create higher quality / stable UI, and be more easily set up to support multiple screen sizes and all of Apple’s platforms.
Also published on Medium.