I struggled with the title for this question, it is hard to summarize into a one-liner. I will try to keep it as straight to the point as possible.
I am developing an app where I am displaying a custom UIView (a chart) and a UITableView with data. Each row in the tableview represent a point in time with a value, lets say its Account Balance.
The tableview only displays 3 rows at a time and the middle row acts as the “active” row. The active row is used to decide what is displayed in the chart. Any AccountBalance with a timestamp either < 12hours before or after is displayed in the chart. Making the chart display a 24 hour window of data.
This is where I am struggling to decide what would be the best design approach in terms of optimizing and reduce lag when scrolling in the tableview. Basicly I have logic to determine which row is in the middle by using UIScrollView delegate methods. This works fine.
To decide what data to display I perform a NSFetchRequest with a predicate everytime the middle row changes (a new request everytime the row changes). When this is complete I call setNeedsDisplay on the chart-view and it is redrawn.
While this works fine at a small dataset so far I have a gut feeling that I could somehow leverage Core Data’s performance and caching better to reduce lag even more. Any ideas and thoughts are much appriciated.
This might not be a common problem and not interest many people, but I figure a discussion about best practise here could apply to more situations than mine, and hence be of value to more people.
What you probably want to use is batch fetching (
NSFetchRequestallows you to set the batch offset and size). That’s exactly what theNSFetchedResultsControlleruses to make sure it only fetches a few objects at a time.You need to be aware that there’s a balance to be made: If you have a large batch size (e.g. 300 rows / objects), you force CoreData to create 300 objects at a time (as opposed to a smaller number). But if you set the batch size to something small (e.g. 3 rows / objects) you’ll pay a high price because you’ll end up pulling in batches very often (which is very expensive).
You’ll have to test to see what batch size is good for you, but it’s typically something like twice the number of objects you’re displaying at once.
The array that the
NSFetchRequestreturns when you turn on batch fetching (by setting a batch size) will do some magic behind your back and it’ll only fill in that array as you iterate through it. And it’ll only keep objects in memory for a few batches before and after what you’re currently using.It’s very easy to misuse batch fetching and make things slower. E.g. if you have an array that’s batch fetching and you have some (broken) logic that loops through all objects, you’ll end up pulling in all batches in the set one by one — defeating the purpose of batch fetching.