The SwiftUI Detour

I recently released version 2.12 of Sofa. That release brought new features, but more importantly, included a major refactoring of the app. This was triggered by two announcements at this year’s WWDC:

  1. UITableView will eventually (soon?) be deprecated
  2. SwiftUI evolved in nice ways and could potentially be used to build a full app

99% of the views in Sofa were table views. Seeing the writing on the wall, I wanted to start tackling this right away. My path, though, wasn’t clear. Should I stick with UIKit and replace my table views with collection views or go in the SwiftUI direction? Either way I had to learn new APIs so I decided to take time to experiment.

The SwiftUI experiment

Since SwiftUI is the future of Apple development, I initially chose this path. I wanted to time-box my efforts to a few weeks in case things didn’t work out.

I started building out the main parts of the app like Home and Lists. It was slow at first, but quickly sped up once I got more comfortable. I hit snags with theming and search, but was able to hack around those by diving into UIKit when necessary.

List concept built with SwiftUI

After a few weeks I was making, and seeing, good progress. This was so encouraging that I decided to go all in and rewrite the entire app in SwiftUI. For those of you with sense, you’ll see where this is headed 🙃.

After a few more weeks things started to get dicey. I was running into bugs and having major performance issues. I tried a lot of different things with the layout, data model, and more to improve performance, but it was clear that I couldn’t in good conscience ship this to people. The product would be noticeably worse.

Back to UIKit

Around late-August I decided I needed to abandon SwiftUI for now and jump back into UIKit. Instantly, my performance issues were gone and things were feeling smooth and snappy. Phew!

The downside was I had a steep learning curve ahead of me. Having to learn UIDiffableDataSource and UICollectionView with Compositional Layout was not trivial.

Again, up to this point, Sofa was driven by NSPersistentCloudKitContainer, NSFetchedResultsController, and UITableView. Getting NSPersistentCloudKitContainer and NSFetchedResultsController to work with UIDiffableDataSource was insanely confusing. There is so little documentation on this setup that at times I wasn’t sure it was possible or recommended.

Luckily the internet is amazing and I was able to piece together a solution by learning how to create a view model driven by NSFetchedResultsController and then sync those changes with to my UIViewController via Combine.

If there’s interest, I’m happy to write in more detail about the solution I went with. All I’ll say for now is that this setup works great. UIDiffableDataSource is much more reliable to work with than messing directly with the NSFetchedResultsController. Oh yea, Compositional Layouts are 🤯. Totally worth the pain of learning.

Did I waste my time with SwiftUI?

No way! I had to learn it to make widgets anyway and it had a couple of other benefits.

Learning the basics of Combine

Since Combine is baked into SwiftUI with things like @ObservableObject I was able to understand the basics fairly quickly. This made using Combine in UIKit much easier to understand and get working.

Prototype of “The Pile” built with SwiftUI

Quickly prototyping ideas

I experimented a lot with the new design and features in Sofa 2.12. Once I had my footing with SwiftUI, creating views was not only fast, but super fun. I was able to explore a bunch of ideas, with real data, and play with it on my devices. This blows every single design and prototyping tool out of the water.

The people who helped

I have so much gratitude for people who take the time to share their hard-won knowledge. Not only do they fill important gaps in Apple’s documentation, but they explain in ways that newbies like me can understand. Thank you!

These links helped me ship:

A worthwhile detour

The detour was worth it, even if I had to double back more than I originally anticipated. The app is in a much more reliable and modern place than it was six months ago. Bonus, I got to learn more stuff!

My plan going forward is to stick with UIKit for the core parts of the app and sprinkle in SwiftUI where it makes sense.

If you want to see the fruits of my labor, you can download Sofa for free from the App Store.