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:

Create Events Demo

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 create EKEvents 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”:

Save Event Sig Kill Error

Save Event Bad Access Error

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.

comments powered by Disqus