How to create iOS reminders programatically with alarms or recurrences
Learn how you can create reminders that will show in the Reminders app. With alarms and recurrences.
Published: July 11, 2020 Sponsored I want a Press KitIn this EventKit post let's go over reminders represented with the EKReminder
class and see how we can create reminders (programatically) that are then displayed in the Reminders app. This can be very useful when you are not building a reminder app but still want to offer reminder functionality to the users.
With EventKit the frameworks and Apple's Reminders app do all the hard work for you. Including sending notifications, handling time and more if you configure recurring events or alarms.
Modifying Info.plist
Same as with calendars for working with user's reminders we need to first request permission. Start by adding the key NSRemindersUsageDescription
to Info.plist
and explain why do you need the permission.
Requesting permissions
We also need to prepare an instance of EKEventStore
which will manage saving events and getting default calendar.
let store = EKEventStore()
Then we can call method to request the permissions.
func askForPermission(grantedAction: @escaping () -> Void) {
store.requestAccess(to: .reminder) { (granted, error) in
if let error = error {
print(error)
return
}
if granted {
grantedAction()
}
}
}
This is simplified example. In a real app we would also have code to handle case when user did not grant an access. Maybe even some error handling but docs don't specify any errors that could occur.
Creating reminder
Assuming we got access we can proceed to actually create the reminder. The code below belongs to the grantedAction
closure but I am not nesting it here for better readability.
EKReminder
needs associated calendar instance otherwise saving will throw an error. We can get the default one like this:
guard let calendar = self.store.defaultCalendarForNewReminders() else { return }
If you wanted to let user select which calendar to use, EventKitUI
has solution named EKCalendarChooser
exactly for this.
Now let's create reminder and set its title and calendar:
let newReminder = EKReminder(eventStore: store)
newReminder.calendar = calendar
newReminder.title = "Buy coffee"
Saving reminder
This is the absolutely minimal setup we need to save the reminder. You can try it by calling save
method available on the EKEventStore
try! store.save(newReminder, commit: true)
I am using try!
since this is an example and it immediately alerts me to a problem. I would not recommend it in a real app.
If you were to save multiple reminders then it would a good idea to set commit
to false
and as a last step call commit
on the EKEventStore
to save them all.
More reminder options
We can provide lots more information about the reminder. For example notes
which is suitable for longer text and we can also set a priority
although this is a bit cumbersome as you will see.
The priority
is a simple int
but the Reminders app has three priorities available and we can get those using the EKReminderPriority
enum whose rawValue
is UInt
because I guess a negative priority does not make sense and the final code would look like this:
newReminder.priority = Int(EKReminderPriority.high.rawValue)
newReminder.notes = "Costa Rica or Brazil"
Not the most elegant code but it works well enough.
There is also isCompleted
property we can use to mark the reminder as done. Don't forget to save the reminder afterwards.
By default reminders don't have a due date but we can set one ourselves. The EKReminder
uses DateComponents
to allow to set a date plus timezone in one go. If you don't specify a timezone it will default to the system one which is nice. Apple also notes in the docs that the components should be created with Gregorian calendar otherwise you will get an error.
let dueDate = Date().addingTimeInterval(60 * 60 * 24 * 3)
newReminder.dueDateComponents = Calendar.current.dateComponents([.year, .month, .day], from: dueDate)
The example above will set the due date three days into the future. Since we are not specifying hours and minutes the event will be all day.
Alarms and recurring reminders
And lastly let's briefly look at setting an alarm and recurring reminders.
Alarm (represented by the EKAlarm
class) actually sounds really simple but it offers a lot of options. The simplest is firing the alarm exactly at the due date. We can either supply the Date
itself or set zero time offset. The relativeOffset
can also be of course used to fire the alarm like 15 minutes before the due date.
Reminders app allows users to set alarms for specific location and we can do that too. We can create instance of EKStructuredLocation
and set it to alarm's structuredLocation
property.
There is also proximity
property which lets us set whether we want the alarm to fire when user enters the location or leaves it.
Once you have an alarm instance you can use addAlarm
on the EKReminder
to add it.
Finally let's look at setting up recurring reminders. This is done by creating an instance of EKRecurrenceRule
we can further configure. It is pretty flexible. For example this one sets weekly recurrence and it will end after 10 events:
EKRecurrenceRule(recurrenceWith: .weekly, interval: 1, end: .init(occurrenceCount: 10))
And like with alarm we can use addRecurrenceRule
to add it to our reminder. There is also a method to remove it and hasRecurrences
to quickly check if any exists. This is a bit tricky because together with the recurrenceRules
array it implies we can set multiple but you can have either none or one.
If you were to add second rule the first one gets removed automatically. From the docs:
The implementation only supports a single recurrence rule. Adding a recurrence rule replaces the single recurrence rule.
There is still a lot more we could go into but I wanted something akin to short overview than exhausting documentation on EKReminder
and all the options. If you liked the article and want more on EventKit
you can check the whole series or let me know on twitter - @nemecek_f - if anything is missing.
Thanks for reading!
Uses: Xcode 12 & Swift 5.3