Image for How to create iOS reminders in code with alarms or recurrences

How to create iOS reminders in code with alarms or recurrences

Create reminders in the Reminders app from Swift code with not that much code. Let's see how.

In this EventKit post let's go over reminders represented with the EKReminder class and see how we can create reminders 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.

Getting permissions

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.

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"

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.

Reminders demo Dark Mode

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 11 & Swift 5