I'm currently adapting my iOS App Bus Stops for iOS 13. It shows the schedule for nearby bus stops in the wider London area. For the next iOS version I decided to
- revise accessibility for voice control
- add Darkmode support
- take advantage of SF Symbols to replace some of my app assets
- replace my own collection diffing algorithm with Swift 5's built in one
- use UITableViewDiffableDataSource / UICollectionViewDiffableDataSource datasource
- flatten my view hierarchy with UICollectionView's compositional layout
The current Betas (the latest Beta is Beta 7 as of this writing) take away some of the joy and excitement one gets when working with new software. Hence I'd like to write down my current experience in regards to implementing the aforementioned features.
XCode 11 has support for switching between Lightmode and Darkmode. One of the problem I ran into is that it crashes the app. Of course you can alternatively
- change Darkmode / Lightmode via Settings - Display & Brightness
- use the Darkmode / Lightmode custom control or
- tell Siri to switch to Darkmode / Lightmode
When there's a change in the Darkmode / Lightmode setting, the app will be notified via traitcollectionDidChange:. In the simulator however I got sometimes mixed results i.e. some parts of the UI appeared in Lightmode when I was already in Darkmode or vice versa, which is quite confusing since it's unclear if it's a bug in the app or just a simulator glitch. Hence I ended up testing this feature solely on an actual device.
Ordered Collection Diffing
Although I had my own ordered collection diffing algorithm, I chose to replace it with Swift's built in one. It's just less code I need to maintain. But I'm honestly not a big fan of the API for several reasons:
The results you get back from difference(from:) are of enum type CollectionDifference.Change. To check for inserts or deletions you have to check its associated value. I definitely would have preferred a dictionary or a tuple for this which would have made map / filter or reduce so much easier to work with. It's not the end of the world, just cumbersome.
moves are only available with an additional call to inferringMoves() since it's expensive to calculate those. A move is represented via a delete or an insert operation's associated value. So this means, that you end up with quasi duplicates: a move from a to b is a deletion from position a and an insert at position b. So when you filter your inserts for b you get that move and you get it again when you filter your deletions for a. Combine this with determining inserts / deletes via associated values and it's cumbersome times two. Why not add a dedicated .move enum type to CollectionDifference.Change? It would have been so much easier. I guess this is the downside of not actively participating in Swift evolution.
UITableViewDiffableDataSource / UICollectionViewDiffableDataSource
First of all, you can't use them with iOS 13 Beta 6 or 7. There's a linker issue and the app just crashes. So I am waiting for XCode Beta 6 and/or iOS Beta 8 to fix this issue. It was fine in Beta 5 and before when I added this feature. Apart from that there are also some issues with the API.
The implementation is obviously based on Swift 5's Ordered Collection Diffing API. The API works fine if it's just about visualising insertions, deletions & moves. I, however, was also interested in the objects that didn't change along with those that moved positions. Why? It's because I need to keep my UI up to date and even a few seconds matter:
- I can ignore deletions because they are removed from the UI
- I can ignore inserts (with no associated move) because they are by definition up to date
- I need however refresh moved items because they have been in the UI before, just at a different position and might indeed be in need of a refresh.
- This also applies to items that have been unchanged as far as their position is concerned.
If you are interested in this information, you have to do ordered collection diffing yourself again. Why this information is not exposed in tableview / collectionview datasources itself, I don't understand at all. I could have opted out of this API and relied on my previous implementation. I decided however against it since again even by doing the ordered collection diffing myself (Swift 5’s version of it), I still had less code to maintain.
The reason I wanted to use this feature was because I use horizontal collectionviews in my tableview. As shown in the WWDC demo, compositional layouts allow a horizontal scrollable list in a vertical listview with just one collectionview. This is way more effective (and less code) than my current solution. The problem I ran into with this however is that I also had to rely on UICollectionView headers or supplementary items as they are called. These however see multiple refreshes whenever the collectionview's datasource updates the screen. The consequence is a flickering UI. For this reason I wasn't able to use this class at all. I hope this will be picked up by Apple at some point before the official release.
Last but not least
My app just uses a handful of new API's and I ran into quite a few issues. I wonder what this means for the overall iOS API landscape? We are now about 4 weeks away from the iOS 13 release date and I honestly don't see how Apple can fix all these issues until then. But I’m willing to give Apple the benefit of the doubt. In a few weeks we know more.