EKLocationReminders/EKLocationReminders/MapViewController.m
/*  | 
Copyright (C) 2015 Apple Inc. All Rights Reserved.  | 
See LICENSE.txt for this sample’s licensing information  | 
Abstract:  | 
This view controller displays a map with annotations if the app has access to Reminders and an empty map, otherwise.  | 
Tap any annotation's callout to create a reminder for that location.  | 
*/  | 
#import "MyAnnotation.h"  | 
#import "EKRSConstants.h"  | 
#import "EKRSHelperClass.h"  | 
#import "MapViewController.h"  | 
#import "AddLocationReminder.h"  | 
#import "LocationReminderStore.h"  | 
#import "LocationTabBarController.h"  | 
const double EKLRRegionDelta = 2.12;  | 
const double EKLRRegionLatitude = 37.78699;  | 
const double EKLRRegionLongitude = -122.4401;  | 
static NSString *const EKRSAnnotationAddress = @"address";  | 
static NSString *const EKRSAnnotationLatitude = @"latitude";  | 
static NSString *const EKRSAnnotationLongitude = @"longitude";  | 
static NSString *EKLRLocationsList = @"Locations";  | 
static NSString *EKLRLocationsListExtension = @"plist";  | 
static NSString * const kPinAnnotationViewIdentifier = @"pinAnnotationViewIdentifier";  | 
@interface MapViewController () <CLLocationManagerDelegate>  | 
@property (nonatomic)id<MKAnnotation> selectedAnnotation;  | 
@property (weak, nonatomic) IBOutlet MKMapView *mapView;  | 
@property (nonatomic, strong) CLLocationManager *locationManager;  | 
@property (nonatomic, strong) EKStructuredLocation *selectedStructureLocation;  | 
@property (nonatomic, copy) NSString *currentUserLocationAddress;  | 
@end  | 
@implementation MapViewController  | 
-(id)initWithCoder:(NSCoder *)aDecoder  | 
{ | 
self = [super initWithCoder:aDecoder];  | 
if (self)  | 
    { | 
[[NSNotificationCenter defaultCenter] addObserver:self  | 
selector:@selector(handleLTBControllerNotification:)  | 
name:LTBAccessGrantedNotification  | 
object:nil];  | 
}  | 
return self;  | 
}  | 
#pragma mark - Location Access Methods  | 
- (void)checkLocationServicesAuthorizationStatus  | 
{ | 
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];  | 
switch (status)  | 
    { | 
case kCLAuthorizationStatusAuthorizedWhenInUse:  | 
[self accessGrantedForLocationServices];  | 
break;  | 
case kCLAuthorizationStatusNotDetermined :  | 
[self requestLocationServicesAuthorization];  | 
break;  | 
case kCLAuthorizationStatusDenied:  | 
case kCLAuthorizationStatusRestricted:  | 
        { | 
if (self.mapView.annotations > 0)  | 
            { | 
[self.mapView removeAnnotations:[NSArray arrayWithArray:self.mapView.annotations]];  | 
}  | 
UIAlertController *alert = [EKRSHelperClass alertWithTitle:NSLocalizedString(@"Privacy Warning", nil)  | 
message:NSLocalizedString(@"Access was not granted for Location Services.", nil)];  | 
[self presentViewController:alert animated:YES completion:nil];  | 
}  | 
break;  | 
default:  | 
break;  | 
}  | 
}  | 
-(void)requestLocationServicesAuthorization  | 
{ | 
if (self.locationManager == nil)  | 
    { | 
self.locationManager = [[CLLocationManager alloc] init];  | 
self.locationManager.delegate = self;  | 
}  | 
// Ask for user permission to find our location  | 
[self.locationManager requestWhenInUseAuthorization];  | 
}  | 
#pragma mark - Handle LocationTabBarController Notification  | 
-(void)handleLTBControllerNotification:(NSNotification *)notification  | 
{ | 
[self accessGrantedForReminders];  | 
}  | 
#pragma mark - Handle Location Services Access  | 
/*  | 
This sample uses data from the Locations.plist file to create annotations for the map. Locations.plist includes an array of dictionaries  | 
that each represents the title, latitude, longitude, and address information of an annotation. Additionally, accessGrantedForLocationServices  | 
adds the current user location to Map. Update this file with data formatted as described above if you wish to test reminders around other locations.  | 
Note that you can obtain latitude, longitude, and delta information by following these steps:  | 
1) Implement  | 
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated  | 
2) Zoom or pan to the area you want in Map, then set a breakpoint there to obtain information about the region.  | 
3) Display the latitude, longitude, and delta information by executing po mapview.region in the debugger.  | 
*/  | 
-(void)accessGrantedForLocationServices  | 
{ | 
if (self.mapView.annotations > 0)  | 
    { | 
[self.mapView removeAnnotations:[NSArray arrayWithArray:self.mapView.annotations]];  | 
}  | 
// Locations.plist contains all data required for configuring the map's region and points of interest  | 
NSURL *plistURL = [[NSBundle mainBundle] URLForResource:EKLRLocationsList withExtension:EKLRLocationsListExtension];  | 
NSArray *data = [NSArray arrayWithContentsOfURL:plistURL];  | 
[self.mapView addAnnotations:[self fetchAnnotations:data]];  | 
self.mapView.showsUserLocation = YES;  | 
}  | 
#pragma mark - Handle Reminders Access  | 
-(void)accessGrantedForReminders  | 
{ | 
[self checkLocationServicesAuthorizationStatus];  | 
}  | 
#pragma mark - Fetch Interest Points  | 
-(NSMutableArray *)fetchAnnotations:(NSArray *)locations  | 
{ | 
NSMutableArray *annotations = [[NSMutableArray alloc] initWithCapacity:locations.count];  | 
for (NSDictionary *dict in locations)  | 
    { | 
MyAnnotation *myAnnotation = [[MyAnnotation alloc]initWithTitle:dict[EKRSTitle]  | 
latitude:[dict[EKRSAnnotationLatitude] doubleValue]  | 
longitude:[dict[EKRSAnnotationLongitude] doubleValue]  | 
address:dict[EKRSAnnotationAddress]];  | 
[annotations addObject:myAnnotation];  | 
}  | 
return annotations;  | 
}  | 
#pragma mark - CLLocationManagerDelegate  | 
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error  | 
{ | 
NSLog(@"Error: %@",error.description);  | 
}  | 
// Called when the authorization status changes for Location Services  | 
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status  | 
{ | 
// Check the authorization status and take the appropriate action  | 
[self checkLocationServicesAuthorizationStatus];  | 
}  | 
#pragma mark - MKMapViewDelegate  | 
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation  | 
{ | 
CLLocation *location = [[CLLocation alloc] initWithLatitude: userLocation.coordinate.latitude longitude:userLocation.coordinate.longitude];  | 
CLGeocoder *geocoder = [[CLGeocoder alloc] init];  | 
// Reverse-geocode the current user coordinates  | 
    [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) { | 
if ((placemarks != nil) && (placemarks.count > 0))  | 
        { | 
CLPlacemark *placemark = placemarks.firstObject;  | 
self.currentUserLocationAddress = [NSString stringWithFormat:@"%@ %@ %@",placemark.subThoroughfare, placemark.thoroughfare,placemark.locality];  | 
}  | 
}];  | 
// Create a region using the current user location  | 
MKCoordinateRegion region;  | 
region.span = MKCoordinateSpanMake(EKLRRegionDelta, EKLRRegionDelta);  | 
region.center = CLLocationCoordinate2DMake(userLocation.location.coordinate.latitude, userLocation.location.coordinate.longitude);  | 
[self.mapView setRegion:region animated:YES];  | 
}  | 
- (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>)annotation  | 
{ | 
MKPinAnnotationView *pinView =(MKPinAnnotationView *) [self.mapView dequeueReusableAnnotationViewWithIdentifier:kPinAnnotationViewIdentifier];  | 
if (!pinView)  | 
    { | 
pinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation  | 
reuseIdentifier:kPinAnnotationViewIdentifier];  | 
if ([pinView respondsToSelector:@selector(pinTintColor)])  | 
        { | 
((MKPinAnnotationView *)pinView).pinTintColor = [MKPinAnnotationView purplePinColor];  | 
}  | 
else  | 
        { | 
// ignore this compile warning, since we already have implemented the replacement above  | 
#pragma GCC diagnostic push  | 
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"  | 
((MKPinAnnotationView *)pinView).pinColor = MKPinAnnotationColorPurple;  | 
#pragma GCC diagnostic pop  | 
}  | 
pinView.animatesDrop = YES;  | 
pinView.canShowCallout = YES;  | 
pinView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];  | 
}  | 
else  | 
    { | 
pinView.annotation = annotation;  | 
}  | 
return pinView;  | 
}  | 
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)view calloutAccessoryControlTapped:(UIControl *)control  | 
{ | 
UIStoryboard *story = [UIStoryboard storyboardWithName:@"LocationReminders" bundle:nil];  | 
UINavigationController *navigationController = (UINavigationController *)[story instantiateViewControllerWithIdentifier:@"navAddLocationReminderVCID"];  | 
AddLocationReminder *addLocationReminderViewController = (AddLocationReminder *)navigationController.topViewController;  | 
if ([view.annotation isKindOfClass:[MyAnnotation class]])  | 
    { | 
MyAnnotation *myAnnotation = (MyAnnotation *)view.annotation;  | 
addLocationReminderViewController.name = myAnnotation.title;  | 
addLocationReminderViewController.address = myAnnotation.address;  | 
}  | 
else  | 
    { | 
MKUserLocation *userLocation = view.annotation;  | 
// We selected the user location  | 
addLocationReminderViewController.name = userLocation.title;  | 
addLocationReminderViewController.address = self.currentUserLocationAddress;  | 
}  | 
self.selectedAnnotation = view.annotation;  | 
[self.navigationController presentViewController:navigationController animated:YES completion:nil];  | 
}  | 
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated  | 
{ | 
}  | 
#pragma mark - Unwind Segues  | 
// Dismiss the Add Location Reminder view controller  | 
- (IBAction)cancel:(UIStoryboardSegue*)sender  | 
{ | 
}  | 
- (IBAction)done:(UIStoryboardSegue*)sender  | 
{ | 
AddLocationReminder *addLocationReminderViewController = (AddLocationReminder *)sender.sourceViewController;  | 
NSDictionary *dictionary = addLocationReminderViewController.userInput;  | 
// If the selected annotation is the current user location, show its address rather than Current Location. Show its title, otherwise.  | 
EKStructuredLocation *location = ([self.selectedAnnotation isKindOfClass:[MKUserLocation class]]) ? [EKStructuredLocation locationWithTitle:self.currentUserLocationAddress] :[EKStructuredLocation locationWithTitle:self.selectedAnnotation.title];  | 
location.geoLocation = [[CLLocation alloc] initWithLatitude:self.selectedAnnotation.coordinate.latitude  | 
longitude:self.selectedAnnotation.coordinate.longitude];  | 
// Convert from miles to meters before assigning it to the radius property  | 
location.radius = kMeter *[dictionary[EKRSLocationRadius] doubleValue];  | 
LocationReminder *newLocationReminder = [[LocationReminder alloc] initWithTitle:dictionary[EKRSTitle]  | 
proximity:dictionary[EKRSLocationProximity]  | 
structureLocation:location];  | 
[[LocationReminderStore sharedInstance] createLocationReminder:newLocationReminder];  | 
}  | 
#pragma mark - Memory Management  | 
- (void)didReceiveMemoryWarning  | 
{ | 
[super didReceiveMemoryWarning];  | 
}  | 
- (void)dealloc  | 
{ | 
[[NSNotificationCenter defaultCenter] removeObserver:self  | 
name:LTBAccessGrantedNotification  | 
object:nil];  | 
}  | 
@end  | 
Copyright © 2015 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2015-11-13