Why we ship Swift, not SwiftUI
Every WWDC since 2019 has pushed SwiftUI a little harder, and every time we start a new app we sit down as a team to ask the same question: does it earn its way into our apps yet? So far the answer has been no for the parts that matter — and probably-yes for the parts that don’t.
This isn’t a verdict on SwiftUI in general. Plenty of teams ship excellent apps with it. It’s a description of where it fits for us: a small studio maintaining several iPhone and iPad apps at once, with no room for surprises in any of them.
What works
SwiftUI is genuinely great for static settings screens, form layouts, anything where the view tree is small and the data flow is one-way. We use it. We also use it for previews while we’re designing — the iteration loop is faster than UIKit’s.
In practice that means the screen where you pick units or export your data is often SwiftUI, embedded inside an app whose main screens are UIKit. The two coexist without much friction, and mixing them lets us use each where it’s strongest instead of committing a whole app to one approach.
What doesn’t (for us)
The moment a screen needs custom gestures, performance-sensitive lists, deep navigation state, or precise animation timing, we drop back to UIKit. The reason isn’t hype — it’s the kind of bugs we see when we don’t. SwiftUI has gotten dramatically better over its recent releases, but it still surprises us at runtime in ways UIKit rarely does.
Concrete cases help. A typing trainer needs every keystroke to land on the right character with no visible delay, and the screen to keep pace with the user’s fingers. A long history of logged entries in a tracker needs to scroll smoothly on an older phone. A planner with drag-and-drop needs gestures that don’t fight the system’s own. Those are the kinds of screens where we’ve found UIKit more predictable.
The trade-offs
Sticking with UIKit isn’t free. It means more code for the same screen, and it means anyone joining has to be comfortable with an older framework that tutorials increasingly skip. Some new system features arrive in SwiftUI first, and adopting them from UIKit takes extra plumbing. We also have to be honest that part of our caution is familiarity: knowing a framework deeply is worth something, but it can also become an excuse.
There’s an open question, too. Our iPhone and iPad apps already run on Apple-silicon Macs, and native Mac apps are in our plans. If SwiftUI makes sharing interface code across those platforms meaningfully easier, the calculation could change.
What we got wrong
We once used SwiftUI for a screen that looked simple on paper and turned out not to be: a list with custom swipe actions and state that changed as you scrolled. It behaved well in previews and strangely on real devices. Rebuilding it in UIKit cost more time than starting there would have. Now we decide per screen, up front, based on what the screen actually has to do.
That’s the only real test: will this surprise us in production? For most of what we build, the answer rules out SwiftUI for the core. We’ll revisit it again next year.