Data Entry with SwiftUI and UIKit

Version 1.0 of Retrospective Timelines was written completely in SwiftUI and while I’m excited to keep working in SwiftUI, there were some issues and limitations that it imposed on my app.

You can’t really talk about SwiftUI without someone pointing out that it’s not “ready” to be used in production yet. I mostly disagree with that sentiment, but when it comes to data entry forms it rings true. Many of the common UI controls in SwiftUI have the most basic implementation possible, often with little to no ability to customize them.

SwiftUI TextField for example.

  • No way to dismiss the keyboard (you can press Return, but a lot of users don’t think to try that)
  • Text selection in the field is really flakey.
  • No SwiftUI equivalent of TextView, so multi-line text is not possible
  • Speech to Text fails. I’ve tried this on every device I have and it fails 100% of the time. It will insert the first character from the first word you speak, then quit listening. I reported this bug months ago.

These issues and limitations were reflecting poorly on the app and giving my users the wrong impression so I decided to do something about it.

My first attempt was to wrap the UIKit controls in SwiftUI wrappers, but I had little success. I cobbled together a sort-of-working version of UITextField, but it was buggy and unreliable. It was also super slow. Rather than keep spending time on it, I decided to just write the entire screens in UIKit.

In Retrospective Timelines all data entry is done in a modal view. There are only two data entry forms and a limited number of ways to open them. I had already disregarded SwiftUIs sheet presentation due to its limitations and instead was using an environmental variable to get the hosting View Controller to use for presentation. All had to do was change the View Controller that I was presenting from the SwiftUI hosting controller I was showing, to a new UIKt version.

I don’t know a ton about UIKit, so it took me a couple of days to make these forms. I used a storyboard for the view controllers and some XIBs for small elements like collection and table view cells. The forms are basically static UITableViewController objects with a ton of customization. Setting these up and accounting for all of the edge cases was a lot more work than the same thing in SwiftUI. I found myself missing the way SwiftUI handle the state of data.

The end result turned to better than I thought possible, so I can’t really complain. Not only did I work around the limitations of the SwiftUI controls, I also ended up with a far better version of the Color and Image pickers for Timelines.