SaltyNuts
SaltyNuts

Reputation: 5168

Attempting to save an event in EKEventStore crashes the app

I have a very odd bug in my app. Attempting to save an event using saveEvent causes the app to continue in one of 3 ways:

In trying to debug this, I've stripped the app to just the view controller listing the events, with a button to add a new one. The first time I present the view controller to add an event, everything goes smoothly, but the second time I do this, it throws an error.

Here is the code I use:

self.event = EKEvent(eventStore: self.eventStore!)
self.event!.calendar = self.calendar!
self.event!.startDate = self.defaultStartDate()
self.event!.endDate = self.event!.startDate.dateByAddingTimeInterval(3600)
var error: NSError?
self.eventStore!.saveEvent(self.event!, span:EKSpanThisEvent, error: &error)
if let e = error {
    println("Saving error: \(error)")
}

If the values for calendar, startDate or endDate are invalid, I get a descriptive error with no crash, but here it crashes at the self.eventStore!.saveEvent(). Any help is appreciated!

Edit Turns out it was due to an extraneous call to self.eventStore.reset().

Upvotes: 1

Views: 1537

Answers (1)

Luca Davanzo
Luca Davanzo

Reputation: 21520

After a long search I find the solution.
You have to save your events in background embedding code on a dispatch_async block.

enum UWCalendarError: Int {
    case AlreadyExists 
    case Generic
    case NotGranted 
}

class Calendar {

static func saveEvent(title: String, startDate: NSDate, duration: NSTimeInterval, completion: (success: Bool, error: UWCalendarError?) -> Void) {

    if Calendar.isEventAlreadyScheduled(title, startDate: startDate, duration: duration) {
        completion(success: false, error: .AlreadyExists)
    } else {
        dispatch_async(dispatch_get_main_queue(),{
            let store = EKEventStore()
            store.requestAccessToEntityType(EKEntityTypeEvent) {(granted, error) in
                if !granted {
                    completion(success: false, error: .NotGranted)
                }
                var event = EKEvent(eventStore: store)
                event.title = title
                event.startDate = startDate
                event.endDate = event.startDate.dateByAddingTimeInterval(duration)
                event.calendar = store.defaultCalendarForNewEvents
                var err: NSError?
                store.saveEvent(event, span: EKSpanThisEvent, commit: true, error: &err)
                if err == nil {
                    completion(success: true, error: nil)
                } else {
                    completion(success: false, error: .Generic)
                }
            }
        })
    }
}

static func isEventAlreadyScheduled(title: String, startDate: NSDate, duration: NSTimeInterval) -> Bool {

    let endDate = startDate.dateByAddingTimeInterval(duration)
    let eventStore = EKEventStore()
    let predicate = eventStore.predicateForEventsWithStartDate(startDate, endDate: endDate, calendars: nil)
    let events = eventStore.eventsMatchingPredicate(predicate)

    if events == nil {
        return false
    }

    for eventToCheck in events {
        if eventToCheck.title == title {
            return true
        }
    }

    return false
}

}

Upvotes: 1

Related Questions