Creating Calendar Events with Event Kit and Swift
Folks have asked more about working with Event Kit and Swift, so the series continues with this guide on how to create calendar events with Event Kit and Swift!
Previous guides in the series include the following:
Demo
Here’s what we’re going for by the end of this:
As with my other guides, I’ve included a working project on GitHub for you to peruse and tinker with:
Code Example
The majority of the work to create an event happens in the example project’s AddEventViewController.swift file, so that’s where I’ll spend my time in this guide. First, let’s put the relevant code before us:
1class AddEventViewController: UIViewController {
2
3 var calendar: EKCalendar! // Intended to be set in parent controller's prepareForSegue event
4
5 @IBOutlet weak var eventNameTextField: UITextField!
6 @IBOutlet weak var eventStartDatePicker: UIDatePicker!
7 @IBOutlet weak var eventEndDatePicker: UIDatePicker!
8
9 // ...
10
11 @IBAction func addEventButtonTapped(sender: UIBarButtonItem) {
12 // Create an Event Store instance
13 let eventStore = EKEventStore();
14
15 // Use Event Store to create a new calendar instance
16 if let calendarForEvent = eventStore.calendarWithIdentifier(self.calendar.calendarIdentifier)
17 {
18 let newEvent = EKEvent(eventStore: eventStore)
19
20 newEvent.calendar = calendarForEvent
21 newEvent.title = self.eventNameTextField.text ?? "Some Event Name"
22 newEvent.startDate = self.eventStartDatePicker.date
23 newEvent.endDate = self.eventEndDatePicker.date
24
25 // Save the calendar using the Event Store instance
26
27 do {
28 try eventStore.saveEvent(newEvent, span: .ThisEvent, commit: true)
29 delegate?.eventDidAdd()
30
31 self.dismissViewControllerAnimated(true, completion: nil)
32 } catch {
33 let alert = UIAlertController(title: "Event could not save", message: (error as NSError).localizedDescription, preferredStyle: .Alert)
34 let OKAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
35 alert.addAction(OKAction)
36
37 self.presentViewController(alert, animated: true, completion: nil)
38 }
39 }
40 }
41
42 // ...
43}
Code Walkthrough
The general outline of the code is this:
- Create an instance of
EKEventStore
– this will let you createEKEvents
and save them.
1let newEvent = EKEvent(eventStore: eventStore)
- Pull an
EKCalendar
instance from the Event Store – this will let you associate an event with a calendar.
1if let calendarForEvent = eventStore.calendarWithIdentifier(self.calendar.calendarIdentifier) {
2// ...
3}
- Create a new
EKEvent
instance and set its properties.
1let newEvent = EKEvent(eventStore: eventStore)
2
3newEvent.calendar = calendarForEvent
4newEvent.title = self.eventNameTextField.text ?? "Some Event Name"
5newEvent.startDate = self.eventStartDatePicker.date
6newEvent.endDate = self.eventEndDatePicker.date
- Attempt to save the event with the
EKEventStore
instance that was created first.
1do {
2 try eventStore.saveEvent(newEvent, span: .ThisEvent, commit: true)
3 delegate?.eventDidAdd()
4
5 self.dismissViewControllerAnimated(true, completion: nil)
6} catch {
7 let alert = UIAlertController(title: "Event could not save", message: (error as NSError).localizedDescription, preferredStyle: .Alert)
8 let OKAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
9 alert.addAction(OKAction)
10
11 self.presentViewController(alert, animated: true, completion: nil)
12}
Gotchas
As I was working through this example, I was initially running into trouble when associating my newEvent
with the calendar
that was passed into AddEventViewController
from the parent controller’s prepareForSegue
method.
It turns out that if you retrieve a calendar from one EKEventStore
instance, say, in the previous view controller, and attempt to assign it to an EKEvent
that is associated with a different EKEventStore
instance, things become really unhappy when it comes time to save the event.
Specifically, you’ll get an error that says “Thread 1: signal SIGKILL” followed by “Thread 1: EXC_BAD_ACCESS”:
The fix for this was easy, once I figured out what was going on: Simply re-retrieve a calendar instance using an appropriate calendarIdentifier
from the EKEventStore
instance you’re using to save the EKEvent
with:
1if let calendarForEvent = eventStore.calendarWithIdentifier((self.calendar.calendarIdentifier))
2{
3 let newEvent = EKEvent(eventStore: eventStore)
4
5 newEvent.calendar = calendarForEvent
6
7 // ...
8}
Wrapping up
My focus in this guide was to demonstrate how to create and save and event to a user’s calendar. I intentionally left out a lot of the navigation aspects and prepareForSegue
calls in order to highlight the event creation process itself. Be sure to check out the accompanying Xcode project on GitHub for full details on the flow of the application.