I have a large set of activities that I want to batch save to the calendar. Which calendar is selected by the user. They have the option to export to iCloud calendar or Google calendar. When exporting to iCloud calendar everything runs smoothly. No problems. However, when exporting to Google calendar I am encountering som weird issues. The number of events to be saved is somewhere around 60-90 events. I use the function provided below to export the calendar events in the background. The operation runs fine and during logging all events are included and when iterating over the events they have all receieved an eventIdentifier. However, on every occasion, about 5-10 events are not synced up to Google calendar and not shown on the phones calendar. The events that are not showing are different for each export, so it is not the event itself that is faulty. I have tried so many different approaches, but no success. What I have tried: - Removed the background operation. - Removed calendar status callback. - Moved the function outside of the closure and calling it directly. - Removed the @autorelease. - Checked that the EKEventStore and EKCalendar is alive during the whole operation.
Does anyone of you know a good explanation for this? I checked if google had any limits on saves, but according to the documents the calendar may turn into readonly when importing 10 000+ events in a short time, in which I am not even close to.
I would love any feedback. This is driving me crazy. As I said earlier, iCloud export works just fine.
Here is my export code:
import UIKit
import EventKit
struct Activity {
var title : String!
var startDate : NSDate!
var endDate : NSDate!
}
class CalendarManager: NSObject {
class func saveToCalendarInBackground(activities: [Activity], eventStore: EKEventStore, calendar: EKCalendar, calendarStatus: (status: String!, progress: Float!) -> (), completion:(success: Bool!, error: NSError!) -> ()) -> Void {
//Run the operations on another thread (not main), but do UI updates on the main thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
if activities.count > 0 {
var formatter = NSDateFormatter()
autoreleasepool {
//Save duties to calendar
for (index, activity) in enumerate(activities) {
//Update status
let progress = Float(index + 1) / Float(activities.count)
//Return callbacks on main thread
dispatch_sync(dispatch_get_main_queue(), {
calendarStatus(status: "Saving \(index+1) of \(activities.count)", progress: progress)
})
//Save activity
var event = EKEvent(eventStore: eventStore)
event.calendar = calendar
event.title = activity.title
event.startDate = activity.startDate
event.endDate = activity.endDate
var saveEventError : NSError?
if eventStore.saveEvent(event, span: EKSpanThisEvent, commit: false, error: &saveEventError) {
println("Activity saved. Commit needed.")
}
else {
println("Save error: \(saveEventError?.localizedDescription)")
}
//
}
}
//Save all pending events
var saveAllEventsError : NSError?
if eventStore.commit(&saveAllEventsError) == true{
println("Save all events complete!")
//Return callbacks on main thread
dispatch_async(dispatch_get_main_queue(), {
println("Calendar Save completion.")
calendarStatus(status: "Calendar save complete!", progress: 1)
completion(success: true, error: nil)
})
return
}
else {
//Return callbacks on main thread
dispatch_async(dispatch_get_main_queue(), {
completion(success: false, error: NSError(domain: "Calendar Save Error", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey : "Error batch saving events: \(saveAllEventsError?.localizedDescription)"]))
})
println("Save all events ERROR: \(saveAllEventsError?.localizedDescription)")
return
}
}
else {
//Return callbacks on main thread
dispatch_async(dispatch_get_main_queue(), {
completion(success: false, error: NSError(domain: "Calendar Save Error", code: 0, userInfo: [NSLocalizedFailureReasonErrorKey : "Found no events to save!"]))
})
return
}
})
}
}