How efficiently fetch items from Core Data using NSFetchedResultsController? - ios

In Core Data I have an Entity with a date field and I want to display all items on UI for a specific date range. For example, I want to show a list of items for the current month with the ability to switch the month.
I found that the best way to do this would be using NSFetchedResultsController with using sectionNameKeyPath which would be computed based on the date field like this:
extension MyEntity {
var sectionId: String {
// convert date to year+month_number
}
}
With this solution, I would get separate sections of items for each month and also not have empty pages where there are no items for that date range.
The problem is when there are many items in the storage - it takes too much time to fetch them cause NSFetchedResultsController fetches all of them at once by default. I tried to use fetchLimit, but that does not work for me, because it limits the number of fetched objects, but in my case, I would need to limit the number of fetched sections.
I was also thinking about just having a predicate that would limit the date range like this
date > startOfMonth & date < endOfMonth
But then I don't know if there are any items for that date range and I don't want to show an empty list.
Is there any way I can fetch a limited number of sections? Or maybe there is a better way to do this?

Related

How to create Day item in coredata in one go for a diary app?

Can some body tell me the best way to create the Day entity in Coredata in one go for a diary app?
PS : I know how to make a notes app in which i can insert notes in DB, but if the don't insert notes in a specific day then the day is not shown when fetched.
I can't seem to understand how to put the notes in the respectetive days in core data ?
You could insert all the dates at the start by choosing a start date, an end date, and then using NSCalendar methods to go from one to the other one day at a time. Add a new entry for each date, and you're done.
That would be a really bad design though. It doesn't make sense to create new entries in your persistent store for every possible day you might cover. Better to only store data that you actually need than to waste time and space for data you'll never use.
To show every day in a week or month or whatever, show those dates, don't rely on Core Data to have every possible date. Show every day in the range that your UI covers. Fetch every diary entry for those dates. If there are diary entries on the date, show them. If there are no diary entries for a date, show the date with no entries. Showing every day in a specific range is a function of your controller code. It should choose the dates and ask Core Data what it has for those dates.
Ok, so you should subclass your entities first so they are easier to work with. And then you could add a function that returns an array of the object (entity) that is your diary. e.g
func getData(moc: NSManagedObjectContext) -> [Entity] {
let request: NSFetchRequest<Entity> = Entity.fetchRequest()
do {
let entityData = try moc.fetch(request)
return entityData
} catch {
// Handle errors
}
}
You could then add a predicate to this method that returns specific data inside the entity matching the arguments you pass your predicate. I know this doesn't cover your full question but i hope it helps!

How to Add Value to Log Before Resetting (CoreData & Swift)

Background info: I have a simple tally counter/habit-tracking app that populates a tableview with custom cells - the counters. Tapping on a cell brings up a detailed view of a specific counter that has the name, value, and the time period for that counter (daily/weekly/monthly/yearly/total). I have also stored in CoreData the startDate and endDate for each counter, so each counter resets after a certain time.
What I would like to do: Each time a counter resets (e.g. after a day or a week), I would like its current total value to be added to a log (preferably some sort of array) specific to that counter. This will then populate another tableview so that, after a few weeks, I can look back and see the previous weekly totals and compare it to the current week.
My data structure:
Entity: Counter
Attributes: Value (Int), startDate(NSDate), endDate(NSDate), timePeriod(Int) (Note: For timePeriod, each integer from 0 to 4 represents daily/weekly/monthly/yearly/no reset.)
My question: How can I implement this? Do I create another entity with a date and value attribute that is created each time a counter resets? I'm having trouble visualizing how to do this with CoreData.
P.S. I don't think using tableview and fetch requests is what I'm looking for.
Thanks so much for your help, and ask me if you need any clarification!
The simplest way is to not "reset" the counter but create a new one. You can then easily display the past counters. That would avoid creating a new entity.
To make it even simpler to distinguish them from active counters you could add a flag like active or archived. You could use that flag for a convenient predicate in your fetched results controller.

How to filter result based on birthdate and min/max age values in Parse?

I'm using the Parse iOS SDK. I want to filter users based on their specified age ranges.
I have two tables:
1st, tableUser which has a field titled birthdate with a String data type.
2nd, tableSettings which has two fields minAge and maxAge, both of which are Number types
I want to fetch users from the tableUser class who's age, calculated from birthdate field, falls between the age range specified in the tableSettings class. For example, if the minAge value is 20 and the maxAge value is 25, then I only want to retrieve users with an age between this range.
Is this possible? How would I make such a query?
Your requirement sounds non-trivial with that suboptimal data structure. I'd probably go for cloud code to hide the required logic from the app. This logic would be to query the tableSettings and calculate the date range that applies.
Now that you have this range, it's still hard to use because your other table uses a string representation of the date rather than a true Date type. This really sucks. If you can you should change the date to the correct type, or at least add another column with a correct representation of the date (but then you have to keep them in sync).
Working with dates you can add specific range criteria to your query and life is easy.
Working with strings is compounded in difficulty because you have the day first, so you can't even use BEGINSWITH to filter the query on year and then process the content. It really is a terrible data model for the problem. So this basically leaves you paging through everything doing an explicit conversion of the string to a date and then comparing that to the range.
If you at all can, change the data model. Even if you create a new class (table) specifically for this data and use an afterSave hook to keep them in sync.

Sorting numbers and dates in a KGrid

I have a KGrid in a Lazarus project that contains different columns with numeric, text and date data.
Sorting by the column with text data is OK but sorting by the columns containing numeric or date data does not work at all.
For instance
10,2,3,1,4,21,30 is sorted as 1,10,2,21,3,30,4 in that order.
Does anyone use KGrid and is there a way to change the grid's OnCompareCells event so that the sorting is done correctly?
Thanks.

UItableView sorted by date in sections (and persistence)

I have several HistoryItems which contain an ID, Title and Date.
The Date is an NSDate of the exact time it was added to the history down to the second.
At the moment I just have an NSArray of these objects, the latest HistoryItem added to the end of the NSArray.
How do I make these items display in a UItableView cell in order of date, the latest being in the top, but also each day must have it's own section.
I also need these HistoryItems to be persistent between exit and loading of apps, so should I go with just saving the NSArray to a file, or using CoreData?
Using CoreData will probably be easier since you can use NSFetchedResultsController to manage the sections 'automatically'. Actually using a NSDate as a sectionKeyPath can be a bit problematic but as luck has it Apple has some sample code that you should be able to modify from having a section per month to a section per day.
Going with CoreData also gives you the sorting essentially for free.

Resources