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:
UITableView
will eventually (soon?) be deprecated- 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 for 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.
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
working 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.
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:
- Fetching objects from Core Data in a SwiftUI project by Donny Wals
- Modern table views with diffable data sources by Donny Wals
- NSFetchedResultsController extension to observe relationship changesby Antoine van der Lee
- Getting started with the Combine framework in Swift by Antoine van der Lee
- Working with Modern Collection Views series by NSScreencast
- Building ViewModels with Combine framework by Majid Jabrayilov
- How to build a UICollectionView like the App Store by Paul Hudson
- Swift: How to UICollectionView Compositional Layout by Jonathan Rasmusson
- A bazillion Stack Overflow posts
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.