Best practice for storing repeating dates in CoreData

Hello everyone,

I have an app that lets users create and save meeting information. They can enter a date and set a repeat (like Apple's calendar app) if the meeting repeats every week, every month, every day, etc.

I'm storing these dates in CoreData using a date attribute. My questions are:
  1. Can I store an array of dates in one date attribute in CoreData?

  2. How should I create a repeating rule for the dates? Right now, I let users choose a repeat by using a picker:

Code Block
Picker("Repeats", selection: $repeats) {
       Text("Every week").tag("1")
       Text("Every month").tag("2")
       Text("Every day").tag("3")
}

I'm thinking this will probably involve a few if statements (e.g. if repeats == 1, set this rule, else if repeats == 2, set this rule, etc.)

But what would this rule look like?


Answered by Claude31 in 664125022
Well, I'll make extra effort to help, but it would be much better for you to try, fail, retry and get it.You would learn much more.

I did not test the code below, so there may be some points to correct. In addition, is not specifically written for SwiftUI syntax.

Code Block
// get startDate
let repeats = 2
let startDate = Date() // Change with what you get from the picker
// get endDate
let endDate = Date() // Change with the second date you get from picker
var repeatArray : [Date] = []
var runningDate = startDate
let calendar = Calendar.current
let dateComponents = calendar.dateComponents(
[.calendar, .timeZone, .year, .month, .day], from: runningDate)
// The repeat loop
while runningDate <= endDate {
repeatArray.append(runningDate)
// add increment to runningDate
switch repeats {
case 1 : runningDate = calendar.date(byAdding: .day, value: 1, to: runningDate)! // ?? endDate
case 2 : runningDate = calendar.date(byAdding: .day, value: 7, to: runningDate)!
case 3 : runningDate = calendar.date(byAdding: .month, value: 1, to: runningDate)! // you increment the month
default: break
}
}


Now, it is up to you to fine tune this. Wish you best.
And don't forget to close the thread.
Yes you can:
https://stackoverflow.com/questions/29825604/how-to-save-array-to-coredata

You also need to save the start and end date.
The logic would be to put selection in order
  • day

  • week

  • month

Test would be a simple switch
Code Block
switch repeats {
case 1 : // Do this
case 2 : // Do That
case 3 : // Do something else
default: // Do nothing
}

Thank you for your reply. Given a start date and a repeat pattern (every week, day, etc.), how do I transform that into an array for CoreData?
that is pretty straightforward (here is the logic, not the code itself)

Code Block
- get startDate
- get endDate
- declare repeatArray : [NSDate] = []
- set runningDate = startDate
- while runningDate <= endDate {
append runningDate to the repeatArray
add increment to runningDate
repeats 1 : add 1
repeats 2 : add 7
repeats 3 : you need to increment the month
}

That should be straightforward to code
Hey Claude,

Thanks so much for all your help. I'm actually really new to coding, so I have no idea of how to implement your suggestions above. Is there any way you could help me with the code?

Thanks so much!
Accepted Answer
Well, I'll make extra effort to help, but it would be much better for you to try, fail, retry and get it.You would learn much more.

I did not test the code below, so there may be some points to correct. In addition, is not specifically written for SwiftUI syntax.

Code Block
// get startDate
let repeats = 2
let startDate = Date() // Change with what you get from the picker
// get endDate
let endDate = Date() // Change with the second date you get from picker
var repeatArray : [Date] = []
var runningDate = startDate
let calendar = Calendar.current
let dateComponents = calendar.dateComponents(
[.calendar, .timeZone, .year, .month, .day], from: runningDate)
// The repeat loop
while runningDate <= endDate {
repeatArray.append(runningDate)
// add increment to runningDate
switch repeats {
case 1 : runningDate = calendar.date(byAdding: .day, value: 1, to: runningDate)! // ?? endDate
case 2 : runningDate = calendar.date(byAdding: .day, value: 7, to: runningDate)!
case 3 : runningDate = calendar.date(byAdding: .month, value: 1, to: runningDate)! // you increment the month
default: break
}
}


Now, it is up to you to fine tune this. Wish you best.
And don't forget to close the thread.
To avoid the risk of infinite loop, you could adapt slightly:

Code Block
var stopNow = false
// The repeat loop
while runningDate <= endDate && !stopNow { // If end == start, we have just one day
repeatArray.append(runningDate)
// add increment to runningDate
switch repeats {
case 1 : runningDate = calendar.date(byAdding: .day, value: 1, to: runningDate)! // ?? endDate
case 2 : runningDate = calendar.date(byAdding: .day, value: 7, to: runningDate)!
case 3 : runningDate = calendar.date(byAdding: .month, value: 1, to: runningDate)! // you increment the month
default: stopNow = true
}
}

Another way to do it.
Instead of storing a full list of dates, you could also only store the start and endDate and the repeat factor.
That would be a more compressed form.
And decompress in an array of dates (as in the code above) when you need to use.

Instead of saving the array, you would save a struct containing
  • startDate

  • endDate

  • repeats

Have a look here on how to code this:
https://stackoverflow.com/questions/37876275/how-do-i-store-a-swift-struct-in-core-data-on-ios
Best practice for storing repeating dates in CoreData
 
 
Q