Ever since I got into app development (4 years ago now), I've had the mindset that "no app is an island", and that apps should be in constant contact with a cloud. This invariably means designing and developing clients using Core Data and domain-specific synchronization engines. One of my most sophisticated examples so far is Thirst.
Thirst is a different kind of news reader, one that marries natural language processing (NLP) and machine learning (ML) to quickly and seamlessly present the most compelling topical news to an individual reader at any given moment.
In this post, I want to focus on the power of NSFetchedResultsControllers in presenting rich data views.
When it comes to news readers, one of the key features for me is the ability to quickly and easily understand what's new. In Thirst, we do this with the subtle concept called item freshness, much like RSS aggregators of old, and Mail.app. This is what a typical Thirst newspaper view looks like:
The newspaper consists of 20 topics, arranged in a newspaper-y grid, where each topic shows an image, title, and a series of thumbnails. Each thumbnail represents a fresh comment, tweet, or news article related to that topic.
Touching on a topic brings up a topic detail view like this:
Now as the user peruses and reads the various items in the topic, they are marked as "stale": the numbers dynamically go down in the topic detail view, and the thumbnails dynamically disappear from the topic in the newspaper view.
This is, of course, accomplished using NSFetchedResultsControllers from Core Data. I won't go into the basic of using NSFetchedResultsControllers, as there are plenty of gifted writers who have covered this, such as Ray Wenderlich and Marcus Zarra. Instead, I'd like to articulate the power of Core Data thru numbers:
- Model classes represent 100s of comments, chatter, and news articles, with relationships to 1 or more topics.
- The newspaper uses an NSManagedObjectContent (MOC) and NSFetchedResultsController (FRC) to find all the "active" topics, as defined by our NLP server.
- Each found topic is represented by a topic box object. There are always 20 topics in the newspaper.
- Each topic box has its own MOC as well as 3 FRCs to find all the related model entities for that topic.
So, that's a total of 21 MOCs and 61 FRCs for the one newspaper view. And the performance is buttery smooth.
The take-away here is the MOCs and FRCs are fairly cheap constructs, and you shouldn't be afraid to use them liberally in your code, if the use case warrants it.
There are few more details to achieving this performance:
- Each topic box MOC is a private queue context, so that fetching the results and detecting changes all happen in the background.
- The thumbnail display in each topic box is assembled via an NSOperation on a shared NSOperationQueue.
- None of this would have been possible if it weren't for Michael Heyeck's write up of faulting model objects during MOC merging.
- In the topic detail view, the various tabs indicate how many fresh items are available. Rather than reconstruct the same set of FRCs for each relationship, the tabs use KVO on the topic boxes.