Search code examples
iosswiftcore-locationeventkit

How to trigger an EventKit alarm with Coordinates in Swift


I don't know about anyone else, but EventKit seems to have very little in terms resources and tutorials online for you to refer to for help.

I need to trigger an alarm when a user hits a radius of a set of coordinates, I wasn't sure of the best ay to do this, I was torn between local notifications, and EventKit reminders.

I decided to go for eventKit as I felt that I could do more with more the alarms and it was the most practical way to do it however, having not known much about EventKit i had some issues.

Anyway I've managed to get together and build a sample project which works and triggers an alert when the user leaves their current location, the only problem is, is that I almost want to do the complete opposite of that, I want to trigger an alert when the user enters a set of coordinates, I assume that most of the code is transferrable, however I seem to be stuck on one bit mainly.

// Creates an EKStructuredLocation Instance with a title of "Current Location"
    let location = EKStructuredLocation(title: "Current Location")
    // Uses the last location update extracted from the locations array to supply you're current location
    location.geoLocation = locations.last as! CLLocation


    // Location is added to a newly created alarm instance
    let alarm = EKAlarm()
    alarm.structuredLocation = location
    // This alarm is triggered when the user moves away from the location proximity
    alarm.proximity = EKAlarmProximityLeave
    stationReminder.addAlarm(alarm)

I'm struggling to find how to set the location of the alarm to coordinates rather than users location.

I tried changing this

location.geoLocation = locations.last as! CLLocation

to

location.geoLocation = CLCircularRegion(circularRegionWithCenter: CLLocationCoordinate2D(latitude: 37.33233141, longitude: -122.03121860), radius: 50.0, identifier: "Location1")

but this doesn't work, i believe i am on the right track but i am throwing up this error: Cannot assign a value of type 'CLCircularRegion!' to a value of type 'CLLocation!'

I've tried loads of things with no resolve, does anybody have any experience with this and know how to help?

I also assume i'll have to change the following from this

alarm.proximity = EKAlarmProximityLeave

to this

alarm.proximity = EKAlarmProximityEnter

UPDATE

I've taken on board some comments below and tried a bunch of other things to get this to work, I feel like I am so close but somethings just missing. I cannot get this alarm to trigger. Excuse all the code comments, it's just so you can see some of the attempts i have made at fixing this.

can anyone see anything wrong with this code for the alarm?

func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {

    // Stops location manager from sending further updates
    locationManager.stopUpdatingLocation()

    // Creates a new EKReminder which is named and initialised with text from the UITextField
    let stationReminder = EKReminder(eventStore: appDelegate!.eventStore)
    stationReminder.title = locationText.text

    // Stores the previously created EKReminder in the default calendar
    stationReminder.calendar = appDelegate!.eventStore!.defaultCalendarForNewReminders()

    // Creates an EKStructuredLocation Instance with a title of "Current Location"
    let location = EKStructuredLocation(title: "Destination: Bournemouth Station")
    // Uses the last location update extracted from the locations array to supply you're current location
//        location.geoLocation = locations.last as! CLLocation
//        location.geoLocation = CLCircularRegion(circularRegionWithCenter: CLLocationCoordinate2D(latitude: 37.33233141, longitude: -122.03121860), radius: 50.0, identifier: "Location1")
//        location.geoLocation = CLLocation(latitude: 50.742771, longitude: -1.895072)
    location.radius = 50.0

    location.geoLocation = CLLocation(latitude:50.742771, longitude:-1.895072)
//        location.radius = 10.0 // metres

    // Location is added to a newly created alarm instance
    let alarm = EKAlarm()
    alarm.structuredLocation = location
    // This alarm is triggered when the user moves away from the location proximity
//        alarm.proximity = EKAlarmProximityEnter
    alarm.proximity = EKAlarmProximityEnter // "geofence": we alarm when *arriving*
    // but this will have no effect until Reminders is granted Location access...
    // and in iOS 8 it won't even ask for it until it is launched
    // also, in iOS 8 the separate background usage pref is withdrawn;
    // instead, auth of Reminders for "when in use" covers this...
    // ...because it means "this app *or one of its features* is visible on screen"
    stationReminder.addAlarm(alarm)

    // Now we have a fully configured reminder which we save in the Event Store
    var error: NSError?
    appDelegate!.eventStore?.saveReminder(stationReminder,
        commit: true, error: &error)

    if error != nil {
        println("Reminder failed with error \(error?.localizedDescription)")
    }
}

Solution

  • Looks like EKEvent has an EKStructuredLocation, which you are using correctly. However, you need to be careful of the type of the geoLocation property. It should be a CLLocation, which is not the same as a CLCircularRegion.

    Steps to fix:

    1. check the docs for EKStructuredLocation https://developer.apple.com/library/mac/documentation/EventKit/Reference/EKStructuredLocationClassRef/index.html

    2. set the location.geoLocation to a CLLocation that you create from latitude, longitude coordinates. (check the docs for CLLocation: https://developer.apple.com/library/mac/documentation/CoreLocation/Reference/CLLocation_Class/index.html#//apple_ref/swift/cl/CLLocation) geoLocation = CLLocation(latitude: 37.33233141, longitude: -122.03121860)

    3. set the geoLocation.radius separately location.radius = 50.0
    4. at that point setting proximityEnter should work as you expected