Skip to content

Instantly share code, notes, and snippets.

@lamprosg
Last active December 18, 2017 08:49
Show Gist options
  • Save lamprosg/5046828 to your computer and use it in GitHub Desktop.
Save lamprosg/5046828 to your computer and use it in GitHub Desktop.
(iOS) Core Location & Map Kit
/**************************************/
//Annotation object
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface MapViewAnnotation : NSObject <MKAnnotation>
@property (nonatomic,strong) NSString *title;
@property (nonatomic,strong) NSString *subtitle;
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
-(id) initWithTitle:(NSString *)title subTitle:(NSString*)subtitle AndCoordinate:(CLLocationCoordinate2D)coordinate;
@end
//-------
#import “MapViewAnnotation.h”
@implementation MapViewAnnotation
-(id) initWithTitle:(NSString *)title subTitle:(NSString*)subtitle AndCoordinate:(CLLocationCoordinate2D)coordinate
{
self = [super init];
self.title = title;
self.subtitle = subtitle;
self.coordinate = coordinate;
return self;
}
@end
/**************************************/
//HEADER FILE
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
@interface MapView : MKMapView <MKMapViewDelegate>
@property (nonatomic,strong) NSArray *locations;
@property (nonatomic,strong) NSMutableArray *annotations;
-(void)showMap;
@end
//----------------------------
//IMPLEMENTATION FILE
@implementation MapView {
CLLocationDegrees centerLatitude;
CLLocationDegrees centerLongitude;
double span;
}
-(NSMutableArray*) createAnnotations
{
annotations = [[NSMutableArray alloc] init];
for (NSDictionary *row in locations) {
NSNumber *latitude = [row objectForKey:@”latitude”];
NSNumber *longitude = [row objectForKey:@”longitude”];
NSString *title = [row objectForKey:@”title”];
NSString *subTitle = [row objectForKey:@”subTitle”];
//Create coordinates from the latitude and longitude values
CLLocationCoordinate2D coord;
coord.latitude = latitude.doubleValue;
coord.longitude = longitude.doubleValue;
MapViewAnnotation *annotation = [[MapViewAnnotation alloc] initWithTitle:title subTitle:subtitle AndCoordinate:coord];
[annotations addObject:annotation];
}
return annotations;
}
-(void) zoomToFit {
if (!locations || ![locations count]) {
centerLatitude = centerLongitude = 0.0;
span = 180;
return;
}
// compute center & span based on the min/max of all pin locations & polyline points
// minimum span is 0.04
double minLat = 1000.0;
double minLng = 1000.0;
double maxLat = -1000.0;
double maxLng = -1000.0;
for (NSDictionary *dict in locations) {
NSNumber *latitude = [row objectForKey:@”latitude”];
NSNumber *longitude = [row objectForKey:@”longitude”];
NSString *title = [row objectForKey:@”title”];
minLat = MIN(minLat, [latitude doubleValue]);
minLng = MIN(minLng, [longitude doubleValue]);
maxLat = MAX(maxLat, [latitude doubleValue]);
maxLng = MAX(maxLng, [longitude doubleValue]);
}
centerLatitude = minLat + (maxLat - minLat)/2.0;
centerLongitude = minLng + (maxLng - minLng)/2.0;
double maxDelta = MAX(maxLat - minLat, maxLng - minLng);
span = MIN(MAX(maxDelta*1.05, 0.02), 180);
}
-(void)showMap {
//Remove old annotations except for user's location
NSMutableArray *oldAnnotations = [NSMutableArray arrayWithArray:annotations];
for (int i=0; i<[oldAnnotations count]; ++i) {
if ([[oldAnnotations objectAtIndex:i] class] == MKUserLocation.class) {
[oldAnnotations removeObjectAtIndex:i];
break;
}
}
[self removeAnnotations:oldAnnotations];
//Add fresh annotations
[self addAnnotations:[self createAnnotations]];
[self zoomToFit];
//Set the center location and span
MKCoordinateSpan span;
span.latitudeDelta = span;
span.longitudeDelta = span;
MKCoordinateRegion region;
CLLocationCoordinate2D center;
center.latitude = centerLatitude;
center.longitude = centerLongitude;
self.region.center = center;
self.region.span = span;
self.region = region;
}
//Model class
//Here we'll represent data (coordinates, titles etc.) on the map
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
@interface BIDPlace : NSObject <MKAnnotation>
//Location, title and subtitle of the marker
@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *subtitle;
@property (assign, nonatomic) CLLocationCoordinate2D coordinate;
@end
#import <UIKit/UIKit.h>
//You need to add location kit and map kit to your project
//For the Location framework
#import <CoreLocation/CoreLocation.h>
//Import our model class for the map
#import "BIDPlace.h"
//Added CLLocationManager delegate and MKMapViewDelegate
@interface BIDViewController : UIViewController <CLLocationManagerDelegate> <MKMapViewDelegate>
//Will hold the instance of the Core Location we'll create
@property (strong, nonatomic) CLLocationManager *locationManager;
//We will set this to the location we receive in the first update from the location manager
//This way, if the user has our program running and moves far enough to trigger updates,
//we’ll be able to calculate how far our user moved
@property (strong, nonatomic) CLLocation *startPoint;
@property (assign, nonatomic) CLLocationDistance distanceFromStart;
//Outlets
@property (weak, nonatomic) IBOutlet UILabel *latitudeLabel;
@property (weak, nonatomic) IBOutlet UILabel *longitudeLabel;
@property (weak, nonatomic) IBOutlet UILabel *horizontalAccuracyLabel;
@property (weak, nonatomic) IBOutlet UILabel *altitudeLabel;
@property (weak, nonatomic) IBOutlet UILabel *verticalAccuracyLabel;
@property (weak, nonatomic) IBOutlet UILabel *distanceTraveledLabel;
//Outelet to a map view
@property (weak, nonatomic) IBOutlet MKMapView *mapView;
@end
@implementation BIDViewController
//Initialization
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
if (![CLLocationManager locationServicesEnabled])
{
//Locations are disabled
return;
}
//Allocate the CLLocationManager
self.locationManager = [[CLLocationManager alloc] init];
if ([_locationManager locationServicesEnabled])
{
//Set this controller class as the delegate
_locationManager.delegate = self;
//Set the desired accuracy to the best available
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
/* Notify changes when device has moved x meters.
* Default value is kCLDistanceFilterNone: all movements are reported.
*/
_locationManager.distanceFilter = 10.0f; //Optional
/* Notify heading changes when heading is > 5.
* Default value is kCLHeadingFilterNone: all movements are reported.
*/
_locationManager.headingFilter = 5; //Optional
//Start giving us location updates
[_locationManager startUpdatingLocation];
//In order to run in the background you have to set at the info.plist
//a new line with the key "UIBackgroundModes"
//with the value "location"
//See:
https://gist.github.com/lamprosg/5345446
/**************************************/
//OR
[_locationManager startMonitoringSignificantLocationChanges];
//This initiates the delivery of location events asynchronously
//only when a significant change in the user’s location is detected (ex. different cell tower, every 500m every 5 min)
//does not rely on the value in the distanceFilter property to generate events
//CAN RUN IN THE BACKGROUND (must be set in the info.plist)
//Add to info.plist a new line with the key "Required Background Modes"
//Then select the "App registers for location updates", and you're done
http://mobile.tutsplus.com/tutorials/iphone/ios-multitasking-background-location/
//To stop it:
[_locationManager stopMonitoringSignificantLocationChanges];
/**************************************/
}
/**************************************
Since this class designated itself as the location manager’s delegate,
location updates will come into the
LocationManager:didUpdateLocations:
**************************************/
//Show the user's location on the map
_mapView.showsUserLocation = YES;
//Set map zool level if you want to
//Set map zoom level
MKCoordinateRegion region;
region.center=Eng.locationTracker.currentlocation.coordinate; // Current location
MKCoordinateSpan span;
span.latitudeDelta = 0.007; // From 0.001 to 120
span.longitudeDelta = 0.007;
region.span=span;
[_mapView setRegion:region animated:YES];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark -
#pragma mark CLLocationManagerDelegate Methods
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
//The updated location
CLLocation *newLocation = [locations lastObject];
//Update coordinates
NSString *latitudeString = [NSString stringWithFormat:@"%g\u00B0", newLocation.coordinate.latitude];
_latitudeLabel.text = latitudeString;
NSString *longitudeString = [NSString stringWithFormat:@"%g\u00B0", newLocation.coordinate.longitude];
_longitudeLabel.text = longitudeString;
NSString *horizontalAccuracyString = [NSString stringWithFormat:@"%gm", newLocation.horizontalAccuracy];
_horizontalAccuracyLabel.text = horizontalAccuracyString;
NSString *altitudeString = [NSString stringWithFormat:@"%gm", newLocation.altitude];
_altitudeLabel.text = altitudeString;
NSString *verticalAccuracyString = [NSString stringWithFormat:@"%gm", newLocation.verticalAccuracy];
_verticalAccuracyLabel.text = verticalAccuracyString;
//Negative accuracy means the location is invalid
if (newLocation.verticalAccuracy < 0 || newLocation.horizontalAccuracy < 0)
{
// invalid accuracy
return;
}
//High accuracy means it doesn't know where we are
if (newLocation.horizontalAccuracy > 100 || newLocation.verticalAccuracy > 50) {
// accuracy radius is so large, we don't want to use it
return;
}
if (_startPoint == nil) //If it's the first update, set it as a starting point
{
self.startPoint = newLocation;
self.distanceFromStart = 0;
//Deal with the map
//Create a BIDPlace instance
BIDPlace *start = [[BIDPlace alloc] init];
//Set the starting coordinate
start.coordinate = newLocation.coordinate;
//Set the title and the subtitle of the pin
start.title = @"Start Point";
start.subtitle = @"This is where we started!";
//Pass the object to the map view
[_mapView addAnnotation:start];
/***************************************
You can put more markers on the map this way
by setting new instances of VIDPlace in our case
and then
[_mapview addAnnptation:instance];
****************************************/
//MKCoordinateRegion let's us tell the view which section of the map we want to display
//Using our location coordinates and a pair of distance in meters (wide and tall)
MKCoordinateRegion region;
region = MKCoordinateRegionMakeWithDistance(newLocation.coordinate,100,100);
//Pass the region to the map view
[_mapView setRegion:region animated:YES];
}
else //Else calculate the distance from the starting point
{
self.distanceFromStart = [newLocation distanceFromLocation:_startPoint];
}
//Update the distance label
NSString *distanceString = [NSString stringWithFormat:@"%gm", _distanceFromStart];
_distanceTraveledLabel.text = distanceString;
}
//Error updating
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
//Get the error and display it as an alert
NSString *errorType = (error.code == kCLErrorDenied) ?
@"Access Denied" : @"Unknown Error";
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:@"Error getting Location"
message:errorType
delegate:nil
cancelButtonTitle:@"Okay"
otherButtonTitles:nil];
[alert show];
}
#pragma mark MKMapViewDelegate Methods
//Whenever you call addAnnotation method, the below method is fired
//You have to set the mapview delegate to self first
//ex.
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
// in case it's the user location, we already have an annotation, so just return nil
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
NSLog(@"ViewForAnnotationCalled");
// try to dequeue an existing pin view first
static NSString *annotationIdentifier = @"annotationIdentifier";
MKPinAnnotationView *pinView = (MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (pinView == nil)
{
// if an existing pin view was not available, create one
MKPinAnnotationView *customPinView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
customPinView.animatesDrop = YES;
customPinView.canShowCallout = YES;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:@selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
customPinView.rightCalloutAccessoryView = rightButton;
//Green pins for sell and red for buy
if ([((Record *)[Eng.search.resultsHome objectAtIndex:[(MapAnnotation *)annotation tag]]) type].isSell)
{
customPinView.pinColor = MKPinAnnotationColorGreen;
}
else
{
customPinView.pinColor = MKPinAnnotationColorRed;
}
customPinView.rightCalloutAccessoryView.tag = [(MapAnnotation *)annotation tag];
return [customPinView autorelease];
}
else
{
pinView.annotation = annotation;
//Green pins for sell and red for buy
if ([((Record *)[Eng.search.resultsHome objectAtIndex:[(MapAnnotation *)annotation tag]]) type].isSell)
{
pinView.pinColor = MKPinAnnotationColorGreen;
}
else
{
pinView.pinColor = MKPinAnnotationColorRed;
}
pinView.rightCalloutAccessoryView.tag = [(MapAnnotation *)annotation tag];
}
return pinView;
}
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)annotationView didChangeDragState:(MKAnnotationViewDragState)newState fromOldState:(MKAnnotationViewDragState)oldState
{
//..Whatever you want to happen when the dragging starts or stops
}
@end
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(40.74835, -73.984911);
NSDictionary *address = @{
(NSString *)kABPersonAddressStreetKey: @"350 5th Avenue",
(NSString *)kABPersonAddressCityKey: @"New York",
(NSString *)kABPersonAddressStateKey: @"NY",
(NSString *)kABPersonAddressZIPKey: @"10118",
(NSString *)kABPersonAddressCountryCodeKey: @"US"
};
MKPlacemark *place = [[MKPlacemark alloc] initWithCoordinate:coords addressDictionary:address];
//OR
MKMapItem *mapItem = [[MKMapItem alloc]initWithPlacemark:myplacemark];
/************************************************************************/
//OR
double latitude = 35.0;
double longitude = 1.0;
MKPlacemark *placemark = [[[MKPlacemark alloc] initWithCoordinate:CLLocationCoordinate2DMake(latitude, longitude) addressDictionary:nil] autorelease];
MKMapItem *mapItem = [[[MKMapItem alloc] initWithPlacemark:placemark] autorelease];
[mapItem setName:@"Name of your location"];
[mapItem openInMapsWithLaunchOptions:nil];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:@"350 5th Avenue New York, NY"
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(@"Geocode failed with error: %@", error);
return;
}
if(placemarks && placemarks.count > 0)
{
//For example take the 1st placemark
CLPlacemark *placemark = placemarks[0];
CLLocation *location = placemark.location;
CLLocationCoordinate2D coords = location.coordinate;
NSLog(@"Latitude = %f, Longitude = %f",
coords.latitude, coords.longitude);
}
}
];
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
CLLocation *newLocation = [[CLLocation alloc]initWithLatitude:40.74835
longitude:-73.984911];
[geocoder reverseGeocodeLocation:newLocation
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error) {
NSLog(@"Geocode failed with error: %@", error);
return;
}
if (placemarks && placemarks.count > 0)
{
CLPlacemark *placemark = placemarks[0];
NSDictionary *addressDictionary =
placemark.addressDictionary;
NSString *address = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStreetKey];
NSString *city = [addressDictionary
objectForKey:(NSString *)kABPersonAddressCityKey];
NSString *state = [addressDictionary
objectForKey:(NSString *)kABPersonAddressStateKey];
NSString *zip = [addressDictionary
objectForKey:(NSString *)kABPersonAddressZIPKey];
NSLog(@"%@ %@ %@ %@", address,city, state, zip);
}
}];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyBestForNavigation;
// Start heading updates.
if (locationManager.headingAvailable && locationManager.locationServicesEnabled)
{
locationManager.headingFilter = kCLHeadingFilterNone;
[locationManager startUpdatingLocation]; //Sometimes you need that in order to work
[locationManager startUpdatingHeading];
}
//Delegate method
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
// Use the true heading if it is valid.
[lblAccuracy setText:[NSString stringWithFormat:@"%.1fmi",newHeading.headingAccuracy]];
}
// Create a new location manager
locationManager = [[CLLocationManager alloc] init];
// Set the location manager delegate
[locationManager setDelegate:self];
// Create a new CLRegion based on the lat/long
// position of Apple's main campus
CLLocationCoordinate2D appleLatLong =
CLLocationCoordinate2DMake(37.331691, -122.030751);
CLRegion *appleCampus = [[CLRegion alloc]
initCircularRegionWithCenter:appleLatLong
radius:100
identifier:@"Apple"];
// Start monitoring for our CLRegion using best accuracy
[locationManager startMonitoringForRegion:appleCampus
desiredAccuracy:kCLLocationAccuracyBest];
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
//What happens when you enter the specific region
}
- (void)locationManager:(CLLocationManager *)managerdidExitRegion:(CLRegion *)region
{
//What happens when you exit the specific region
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
//Region monitoring error occured
NSLog(@"Region monitoring failed with error: %@", [error localizedDescription]);
}
//Needs to comfort <MKOverlay> protocol
MKPolyline* polyline = [[MKPolyline alloc] init];
CLLocationCoordinate2D coord[2];
coord[0] = myPreviousLocation;
coord[1] = myCurrentLocation;
polyline = [MKPolyline polylineWithCoordinates:coord count:2];
[self.mapView addOverlay:polyline];
myPreviousLocation = Eng.locationTracker.currentlocation.coordinate;
.....
//Overlay delegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polyLineView = [[MKPolylineView alloc] initWithPolyline:polyline];
polyLineView.fillColor = [UIColor blueColor];
polyLineView.strokeColor = [UIColor blueColor];
polyLineView.lineWidth = 5;
return polyLineView;
}
@lamprosg
Copy link
Author

MKPinkAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:[annotation title]];

pin.animatesDrop = YES;
pin.canShowCallout = YES;
pin.draggable = YES;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment