SwiftUI in 2021: The Good, the Bad, and the Ugly
By: Chrys Bader
Tags: Programming, iOS, Swiftui, Apple, Swift

The Bad

1. Not everything is available in SwiftUI yet

There are a number of components that are missing, incomplete, or overly simple, some of which I’ll go into more detail below.

There is a solution by using UIViewRepresentable UIViewControllerRepresentable and UIHostingController . The former two allow you to embed UIKit views and controllers into a SwiftUI view hierarchy. The latter allows you to embed a SwiftUI view in UIKit. The same three exist for Mac development ( NSViewRepresentable , etc).

These bridges are a great stopgap to make up for the missing functionality that SwiftUI has, but it’s not always a seamless experience. Furthermore, while the cross-platform promise of SwiftUI is great, if something’s not available you’ll still need to implement bridge code twice for iOS and Mac.

2. NavigationView is not really there yet

If you want to hide the navigation bar and still have the swipe gesture work, you can’t. I ended up creating a UINavigationController wrapper from some code I found. It works but it’s not a great solution long-term.

If you want to have a SplitView on iPad, you can’t show the master and detail view together yet in portrait mode. They chose an awkward use of a button to reveal a drawer, which is closed by default. Apparently, you can solve this problem by adding padding, which highlights the kind of things you have to do when wrangling SwiftUI.

NavigationLink is kind of funky when you want to navigate programmatically. Here’s an interesting discussion.

3. Text input is very limited

TextField and TextEditor are too simplistic right now, and you’ll end up falling back on UIKit. I had to build my own UIViewRepresentable for UITextField and UITextView (with auto-growing support). The gists are below:

4. The compiler struggles

When your view gets a little heftier and you’ve factored it out the best you can, the compiler can still huff and puff, telling you:

The compiler couldn’t type-check this expression in a reasonable amount of time…

This has slowed me down a number of times. I’ve gotten good at commenting out code and narrowing it down to the line that’s causing the issue, but it feels really backward to be debugging code like this in 2021.

5. matchedGeometryEffect

When I first discovered this, I thought it was amazing. It’s supposed to help you transition two views with different identities more seamlessly by matching their geometry as one appears and another disappears. I thought this would help make beautiful transitions from View A to View B.

I kept wanting it to work. Ultimately, I stay away from this because it’s imperfect and it causes crashes when you use it in a List or ScrollView with a lot of items. I would only recommend using this for simple transitions within the same view. Things start to get weird when you’re sharing a namespace between multiple distinct views, including view clipping during transitions.

6. Gestures are limited

SwiftUI comes with a new set of gestures (i.e. DragGesture , LongPressGesture ) that can be added to a view using the gesture convenience modifiers like tapGesture and longPressGesture . They work okay until you want to do more complex interactions.

For example, DragGesture doesn’t interact well with ScrollView . Putting one within a ScrollView prevents scrolling, even with the simultaneousGesture modifier. In other situations, a drag gesture can get canceled without any notification, leaving gestures in an incomplete state.

To solve this, I built my own GestureView which allows me to use UIKit gestures in SwiftUI. I’ll share this in my next post about the best SwiftUI libraries and workarounds.

7. SwiftUI in Share Extension

I could be wrong, but Share Extensions still use UIKit. I built a share extension using SwiftUI by leveraging UIHostingController and there was a noticeable delay when the share extension loaded, creating a poor user experience. You can try to mask it by animating the view in, but it still has about a 500ms delay.

Honorable mentions