In my application I have a mapView with several custom pins.
I'm trying to do this: On the showCallout an AlertView appears and tells if you want to calculate the route. This works but just for one location. Or better, only one method gets called, so I've only one destination.
Here's my code (I have 9 destinations, but I post only 2 to make the code shorter):
- (void)viewDidLoad
{
[super viewDidLoad];
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
[mapView setDelegate:(id)self];
MKCoordinateRegion TavernaCongiura = { {0.0, 0.0} , {0.0, 0.0} };
TavernaCongiura.center.latitude = 40.380784;
TavernaCongiura.center.longitude = 15.541373;
TavernaCongiura.span.longitudeDelta = 0.004f;
TavernaCongiura.span.latitudeDelta = 0.004f;
[mapView setRegion:TavernaCongiura animated:YES];
mapView.showsUserLocation = YES;
TeggianoAnnotation *ann0 = [[TeggianoAnnotation alloc] init];
ann0.title = #"Taverna de la Congiura";
ann0.subtitle = #"Antipasto";
ann0.coordinate = TavernaCongiura.center;
[mapView addAnnotation: ann0];
MKCoordinateRegion TavernaDeiMori = { {0.0, 0.0} , {0.0, 0.0} };
TavernaDeiMori.center.latitude = 40.380535;
TavernaDeiMori.center.longitude = 15.542028;
TavernaDeiMori.span.longitudeDelta = 0.004f;
TavernaDeiMori.span.latitudeDelta = 0.004f;
[mapView setRegion:TavernaDeiMori animated:YES];
TeggianoAnnotation *ann1 = [[TeggianoAnnotation alloc] init];
ann1.title = #"Taverna dei Mori";
ann1.subtitle = #"Parmatieddi";
ann1.coordinate = TavernaDeiMori.center;
[mapView addAnnotation: ann1];
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation {
if (newLocation.horizontalAccuracy == oldLocation.horizontalAccuracy) {
[self->locationManager stopUpdatingLocation];
CLLocationCoordinate2D coords = newLocation.coordinate;
NSString *stringURL = [NSString stringWithFormat:#"http://maps.google.com
/maps?saddr=%g,%g&daddr=40.380784,15.541373", coords.latitude, coords.longitude];
NSURL *url = [NSURL URLWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
}
}
- (void)locationManagerMori:(CLLocationManager *)manager didUpdateToLocation:
(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if (newLocation.horizontalAccuracy == oldLocation.horizontalAccuracy) {
[self->locationManager stopUpdatingLocation];
CLLocationCoordinate2D coords = newLocation.coordinate;
NSString *stringURL = [NSString stringWithFormat:#"http://maps.google.com
/maps?saddr=%g,%g&daddr=40.380535,15.542028", coords.latitude, coords.longitude];
NSURL *url = [NSURL URLWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
}
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:
(id<MKAnnotation>)annotation {
MKAnnotationView *MyPin=[[MKAnnotationView alloc] initWithAnnotation:annotation
reuseIdentifier:#"current"];
UIButton *advertButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
if ([[annotation title] isEqualToString:#"Taverna de la Congiura"]) {
[advertButton addTarget:self action:#selector(buttonCongiura:)
forControlEvents:UIControlEventTouchUpInside];
MyPin.image = [UIImage imageNamed:#"CongiuraMappa.png"];
}
if ([[annotation title] isEqualToString:#"Taverna dei Mori"]) {
[advertButton addTarget:self action:#selector(buttonMori:)
forControlEvents:UIControlEventTouchUpInside];
MyPin.image = [UIImage imageNamed:#"MoriMappa.png"];
}
MyPin.rightCalloutAccessoryView = advertButton;
MyPin.draggable = NO;
MyPin.highlighted = YES;
MyPin.canShowCallout = YES;
return MyPin;
}
-(void)buttonCongiura:(id)sender {
UIAlertView *alertViewCongiura;
alertViewCongiura = [[UIAlertView alloc] initWithTitle:#"Taverna de la Congiura"
message:#"Calcola Percorso" delegate:self cancelButtonTitle:#"Annulla"
otherButtonTitles:#"Calcola", nil];
[alertViewCongiura show];
}
-(void)buttonMori:(id)sender {
UIAlertView *alertViewMori;
alertViewMori = [[UIAlertView alloc] initWithTitle:#"Taverna dei Mori"
message:#"Calcola Percorso" delegate:self cancelButtonTitle:#"Annulla"
otherButtonTitles:#"Calcola", nil];
[alertViewMori show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
self->locationManager = [[CLLocationManager alloc] init];
self->locationManager.delegate = (id)self;
[self->locationManager startUpdatingLocation];
}
if (buttonIndex == 2) {
self->locationManagerMori = [[CLLocationManager alloc] init];
self->locationManagerMori.delegate = (id)self;
[self->locationManagerMori startUpdatingLocation];
}
}
The problem is that only the first
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation
is called.
You can't use a different name for the delegate methods for each of the location manager instances you are using. Each location manager will still call the methods defined by the CLLocationManagerDelegate protocol.
You could check which manager is calling by checking if the manager parameter is equal to one of the instances you are creating (eg. if (manager == locationManagerMori)).
But you don't need to create a separate location manager instance for each annotation in the first place.
Instead, keep just one location manager instance and in the delegate method, you can find out what the currently selected annotation is and use its coordinates in the url string. For example:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if (newLocation.horizontalAccuracy == oldLocation.horizontalAccuracy)
//the above if-condition looks a little suspicious by the way
{
if (mapView.selectedAnnotations.count == 0)
{
//no annotation selected, do nothing
return;
}
//there can only be one selected annotation so get the one at index 0
id<MKAnnotation> selectedAnnotation =
[mapView.selectedAnnotations objectAtIndex:0];
[self->locationManager stopUpdatingLocation];
CLLocationCoordinate2D coords = newLocation.coordinate;
NSString *stringURL = [NSString stringWithFormat:
#"http://maps.google.com/maps?saddr=%g,%g&daddr=%g,%g",
coords.latitude, coords.longitude,
selectedAnnotation.coordinate.latitude,
selectedAnnotation.coordinate.longitude];
NSURL *url = [NSURL URLWithString:stringURL];
//stop updating location to avoid possible endless loop
//when user comes back to this app...
[manager stopUpdatingLocation];
[[UIApplication sharedApplication] openURL:url];
}
}
You also don't need a separate button action method for each annotation. You can just create one button action method and use the same technique to get the selected annotation.
Another issue is in the alert view clickedButtonAtIndex method. You seem to be checking which annotation it is by looking at the alert view's button index. That index will be either the Annulla or Calcola button (not which annotation).
Since you won't need to create a separate location manager for each annotation, you won't need to know which annotation the alert view is for. You just need to check whether the user tapped Annulla or Calcola:
if (buttonIndex == alertView.firstOtherButtonIndex)
{
self->locationManager = [[CLLocationManager alloc] init];
self->locationManager.delegate = (id)self;
self->locationManager startUpdatingLocation];
}
Related
Here is my goal:
I have to show the user location with his address on a map every time he open the view that has the MapView and then stop location to save battery. So far i can do it, but if the user moves to another area and enter the view (after leave it) the location does not change.
Here is my code:
- (void)viewDidLoad
{
mapView.mapType = MKMapTypeStandard;
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated{
if(!self.locationManager){
self.locationManager = [[CLLocationManager alloc] init];
}
[self.locationManager startUpdatingLocation];
}
-(void)viewDidDisappear:(BOOL)animated{
self.locationManager = nil;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
MKCoordinateRegion viewRegion =
MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 2000, 2000);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
[manager stopUpdatingLocation];
MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc]
initWithCoordinate:newLocation.coordinate];
geocoder.delegate = self;
[geocoder start];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
MapLocation *annotation = [[MapLocation alloc] init];
annotation.streetAddress = placemark.thoroughfare;
annotation.city = placemark.locality;
annotation.state = placemark.administrativeArea;
annotation.zip = placemark.postalCode;
annotation.coordinate = geocoder.coordinate;
[mapView addAnnotation:annotation];
geocoder.delegate = nil;
}
- (void)openCallout:(id<MKAnnotation>)annotation {
[mapView selectAnnotation:annotation animated:YES];
}
- (MKAnnotationView *) mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>) annotation {
static NSString *placemarkIdentifier = #"Map Location Identifier";
if ([annotation isKindOfClass:[MapLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:placemarkIdentifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:placemarkIdentifier];
}
else{
annotationView.annotation = annotation;
}
annotationView.enabled = YES;
annotationView.canShowCallout = YES;
annotationView.image = [UIImage imageNamed:#"rescue"];
[self performSelector:#selector(openCallout:) withObject:annotation afterDelay:0.5];
return annotationView;
}
return nil;
}
I have a CLLocationManager on another view that get user location without a map (here the location is working just fine). If a start the location on that view and go back to the view with the map it's is updated. Why that?
Any ideias?
- (void)loadView {
MKMapView *mv = [[MKMapView alloc]init];
mapView.showsUserLocation=YES;
mv.delegate=self;
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation{
[mapView setCenterCoordinate:mapView.userLocation.location.coordinate animated:YES];
mapView.showsUserLocation=NO;
}
well to display it on the map
MKMapView *mv = [[MKMapView alloc]init];
CLLocationCoordinate2D c = CLLocationCoordinate2DMake(locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude);
[mv setCenterCoordinate:c animated:YES];
and to stop updating
[locationManager stopUpdatingLocation];
Right now I am setting my region based on users current location. I would like to now set the zoom level so I can see the users current location and the nearest pin that is being pulled in via json.
Not until run time will the app know the number of pins or the locations of said pins.
Here is what I have so far.
#implementation LocationsViewController
#synthesize mapView;
#synthesize locationManager;
#synthesize phone;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
self.title = NSLocalizedString(#"Locations", #"Locations");
self.tabBarItem.image = [UIImage imageNamed:#"locations"];
}
return self;
}
- (void)dealloc
{
[super dealloc];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
//Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"New latitude: %f", newLocation.coordinate.latitude);
NSLog(#"New longitude: %f", newLocation.coordinate.longitude);
MKCoordinateRegion region;
region.center.latitude =newLocation.coordinate.latitude;
region.center.longitude= newLocation.coordinate.longitude;
region.span.longitudeDelta=0.2;
region.span.latitudeDelta =0.2;
[mapView setRegion:region animated:YES];
[mapView setDelegate:self];
//[locationManager stopUpdatingLocation];
}
-(void)viewDidDisappear:(BOOL)animated
{
[locationManager stopUpdatingLocation];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[locationManager startUpdatingLocation];
if([self connectedToNetwork] != YES)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"OH NO!" message:#"To get the latest information you need a data or wi-fi connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
else
{
[mapView removeAnnotations:mapView.annotations];
NSString *urlString = [NSString stringWithFormat:#"http://www.mywebsite.com/json.json"];
NSURL *url = [NSURL URLWithString:urlString];
NSData *data = [NSData dataWithContentsOfURL:url];
NSError *error;
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
for(id key in json) {
id value = [json objectForKey:key];
NSString *titlePin = [value valueForKey:#"address"];
NSString *address = [value valueForKey:#"title"];
NSString *latitude = [value valueForKey:#"latitude"];
NSString *longitude = [value valueForKey:#"longitude"];
NSArray* foo = [address componentsSeparatedByString: #":"];
NSString* address2 = [foo objectAtIndex: 0];
phone = [foo objectAtIndex: 1];
double myLatitude = [latitude doubleValue];
double myLongitude = [longitude doubleValue];
MKCoordinateRegion location1;
location1.center.latitude =myLatitude;
location1.center.longitude= myLongitude;
location1.span.longitudeDelta=0.1;
location1.span.latitudeDelta =0.1;
MapAnnotation *ann1 =[[[MapAnnotation alloc] init] autorelease];
ann1.title=[NSString stringWithFormat:#"%#",titlePin];
ann1.subtitle=[NSString stringWithFormat:#"%#",address2];
ann1.phone=[NSString stringWithFormat:#"%#",phone];
ann1.coordinate= location1.center;
[mapView addAnnotation:ann1];
[phone retain];
}
}
}
-(MKAnnotationView *) mapView:(MKMapView *)mapView2 viewForAnnotation:(id<MKAnnotation>)annotation {
if (annotation == mapView2.userLocation) {
return nil;
}else{
MKPinAnnotationView *MyPin=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#"current"];
MyPin.pinColor = MKPinAnnotationColorPurple;
UIButton *advertButton = [UIButton buttonWithType:UIButtonTypeInfoDark];
[advertButton setImage:[UIImage imageNamed:#"mapphone"] forState:UIControlStateNormal];
[advertButton addTarget:self action:#selector(button:) forControlEvents:UIControlEventTouchUpInside];
MyPin.rightCalloutAccessoryView = advertButton;
MyPin.draggable = NO;
MyPin.highlighted = YES;
MyPin.animatesDrop=TRUE;
MyPin.canShowCallout = YES;
return MyPin;
}
}
-(void)button:(id)sender {
UIButton *button = (UIButton *)sender;
MKPinAnnotationView *annotationView = (MKPinAnnotationView*)button.superview.superview;
MapAnnotation *mapAnnotation = annotationView.annotation;
UIDevice *device = [UIDevice currentDevice];
if ([[device model] isEqualToString:#"iPhone"] ) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:#"tel:%#",mapAnnotation.phone]]];
} else {
UIAlertView *Notpermitted=[[UIAlertView alloc] initWithTitle:mapAnnotation.phone message:#"Your device doesn't support this feature." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[Notpermitted show];
[Notpermitted release];
}
}
- (BOOL) connectedToNetwork
{
Reachability *r = [Reachability reachabilityWithHostName:#"www.google.com"];
NetworkStatus internetStatus = [r currentReachabilityStatus];
BOOL internet;
if ((internetStatus != ReachableViaWiFi) && (internetStatus != ReachableViaWWAN)) {
internet = NO;
} else {
internet = YES;
}
return internet;
}
- (void)viewDidUnload
{
[super viewDidUnload];
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
#end
I did something similar, but based on two annotations, not the user's location. You should be able to replace mapView.centerCoordinate with mapView.userLocation.coordinate.
in viewForAnnotation:
CLLocation *centerLoc = [[CLLocation alloc] initWithLatitude:mapView.centerCoordinate.latitude longitude:mapView.centerCoordinate.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:[annotation coordinate].latitude longitude:[annotation coordinate].longitude];
CLLocationDistance distance = [loc2 distanceFromLocation:centerLoc];
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(mapView.centerCoordinate, distance*2, distance*2);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
Note, this code will re-calc the zoom level each time you add an annotation. You may need to save the distance and only change the map if the new distance is greater than the prior distance.
I am Showing Australia continent when my Map application launch. I have one button on which I want to set coding for current location and zoom in to that location after pressing butoon. I am getting current latitude & longitude and able to pass in Web-service url. I did following coding
- (void)viewDidLoad
{
//to set the australia region
CLLocationCoordinate2D AusLoc = {-19.048230,133.685730};
MKCoordinateSpan AusSpan = MKCoordinateSpanMake(45, 45);
MKCoordinateRegion AusRegion = MKCoordinateRegionMake(AusLoc, AusSpan);
mapView.region = AusRegion;
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation]; }
and
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if((fabs(newLocation.coordinate.latitude) > 0.001) || (fabs(newLocation.coordinate.longitude) > 0.001)) {
NSLog(#"Got location %f,%f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
if (currentLocation != nil) {
[currentLocation release];
}
currentLocation = newLocation;
[currentLocation retain];
}
NSString *lati=[NSString stringWithFormat:#"%f", newLocation.coordinate.latitude];
NSString *longi=[NSString stringWithFormat:#"%f", newLocation.coordinate.longitude];
}
on Search button(web service calling)
NSString *url = [NSString stringWithFormat:#"http://.....url...../hespdirectory/phpsqlsearch_genxml.php?lat=%f&lng=%f&radius=%f",locationManager.location.coordinate.latitude,locationManager.location.coordinate.longitude,radius];
Updated with coding:
- (IBAction) showAddress {
if (locationManager.location == nil)
{
NSLog(#"user location not found yet or service disabled/denied");
}
else
{
// Change map region using span (degrees)...
MKCoordinateSpan span = MKCoordinateSpanMake(0.001, 0.001);
MKCoordinateRegion region = MKCoordinateRegionMake
(locationManager.location.coordinate, span);
[mapView setRegion:region animated:YES];
}
}
When I set mapView.showUserLocation = YES; it shows current location when map application launch that is before tapping button. I am confused with previous answer. So What code should I put under button click event to show current location and also suggest If there is any change to pass current Lati and longi in web service url after giving coding for click event. Thanks in advance
Edited:-
- (MKAnnotationView *) mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
MKPinAnnotationView *annView=[[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:#""];
annView.pinColor = MKPinAnnotationColorGreen;
//annView.animatesDrop=TRUE;
annView.canShowCallout = YES;
annView.calloutOffset = CGPointMake(-5, 5);
annView.enabled = YES;
annView.image = [UIImage imageNamed:#"flagg.png"];
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
annView.rightCalloutAccessoryView = rightButton;
NSLog(#"Created annotation at: %f %f", ((CustomPlacemark*)annotation).coordinate.latitude, ((CustomPlacemark*)annotation).coordinate.longitude);
[annView addObserver:self
forKeyPath:#"selected"
options:NSKeyValueObservingOptionNew
context:#"GMAP_ANNOTATION_SELECTED"];
[annView autorelease];
return annView;
}
//return nil;
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{
NSString *action = (NSString*)context;
// We only want to zoom to location when the annotation is actaully selected. This will trigger also for when it's deselected
if([[change valueForKey:#"new"] intValue] == 1 && [action isEqualToString:#"GMAP_ANNOTATION_SELECTED"])
{
if([((MKAnnotationView*) object).annotation isKindOfClass:[CustomPlacemark class]])
{
CustomPlacemark *place = ((MKAnnotationView*) object).annotation;
// Zoom into the location
[mapView setRegion:place.coordinateRegion animated:TRUE];
NSLog(#"annotation selected: %f %f", ((MKAnnotationView*) object).annotation.coordinate.latitude, ((MKAnnotationView*) object).annotation.coordinate.longitude);
}
}
}
In Search button(calling webservice)
CLLocationCoordinate2D location;
//currentLocation = newLocation;
float radius = [[arrayNo objectAtIndex:[pickerView selectedRowInComponent:0]] floatValue];
//NSURL *url = [[NSURL alloc] initWithString:#"http://www.hettich.com.au/hespdirectory/phpsqlsearch_genxml.php?lat=-33.853468&lng=150.94042160000004&radius=5"];
NSString *url = [NSString stringWithFormat:#"http://www.hettich.com.au/hespdirectory/phpsqlsearch_genxml.php?lat=%f&lng=%f&radius=%f",locationManager.location.coordinate.latitude,locationManager.location.coordinate.longitude,radius];
//NSLog(#"NSString *url");
NSLog(#"%#", url);
NSURL *URL = [NSURL URLWithString:url];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
//Initialize the delegate.
XMLParser *parser = [[XMLParser alloc] initXMLParser];
//Set delegate
[xmlParser setDelegate:parser];
//Start parsing the XML file.
BOOL success = [xmlParser parse];
if(success)
{ resultButton.userInteractionEnabled = YES;
// NSMutableArray* annotations = [[NSMutableArray alloc] init];
for (int i = 0; i < [appDelegate.markers count]; i++)
{
marker *aMarker = [appDelegate.markers objectAtIndex:i];
location.latitude = [aMarker.lat floatValue];
location.longitude =[aMarker.lng floatValue];
AddressAnnotation *annob = [[AddressAnnotation alloc] initWithCoordinate:location];
annob.title = aMarker.name;
annob.subTitle = aMarker.address;
[mapView addAnnotation:annob];
[annob release];
CLLocationCoordinate2D ausLoc = {location.latitude,location.longitude}; //for zoom in the showroom results region
MKCoordinateSpan ausSpan = MKCoordinateSpanMake(0.108889, 0.169922);
MKCoordinateRegion ausRegion = MKCoordinateRegionMake(ausLoc, ausSpan);
NSLog(#"No Errors");
mapView.region = ausRegion;
}
}
In your button tapped method, you should first check if the location manager has obtained a location and then set the map's center or region to the user's location:
if (locationManager.location == nil)
{
NSLog(#"user location not found yet or service disabled/denied");
}
else
{
// Change map center (preserving current zoom level)...
[mapView setCenterCoordinate:locationManager.location.coordinate animated:YES];
// --OR--
// Change map region using distance (meters)...
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance
(locationManager.location.coordinate, 1000, 1000);
[mapView setRegion:region animated:YES];
// --OR--
// Change map region using span (degrees)...
MKCoordinateSpan span = MKCoordinateSpanMake(0.001, 0.001);
MKCoordinateRegion region = MKCoordinateRegionMake
(locationManager.location.coordinate, span);
[mapView setRegion:region animated:YES];
}
In the didUpdateToLocation method, you are setting a "currentLocation" variable but I don't see a need for it. The locationManager already has a location property.
In any case, only considering absolute latitudes or longitudes greater than 0.001 as "valid" is incorrect because a) it excludes locations near the equator or prime meridian (even though you're only interested in Australia this logic is the wrong way to go), and b) it's better instead to check if newLocation itself is nil.
So here's my last query. I've got all my components I need, however, I need the phone to create a string from the geocoder so it can be fed into Google maps. This string is passed to a server, then grabbed from that database into another iPhone by different users. I have the database get/post side finished, but I need the geocoding to work so it can produce an address string. Here's my code: I've used Mark/LaMarche's mapkit tutorial as my foundation. My question is: Can I use the geocoder WITHOUT having to use MapKit? And would that save me more code than what is written below? Thank you!
- (IBAction)findMe {
CLLocationManager *lm = [[CLLocationManager alloc] init];
lm.delegate = self;
lm.desiredAccuracy = kCLLocationAccuracyBest;
[lm startUpdatingLocation];
progressBar.hidden = NO;
progressBar.progress = 0.0;
progressLabel.text = NSLocalizedString(#"Determining Current Location", #"Determining Current Location");
button.hidden = YES;
}
- (void)openCallout:(id<MKAnnotation>)annotation {
progressBar.progress = 1.0;
progressLabel.text = NSLocalizedString(#"Showing Annotation",#"Showing Annotation");
[mapView selectAnnotation:annotation animated:YES];
}
#pragma mark -
- (void)viewDidLoad {
mapView.mapType = MKMapTypeStandard;
// mapView.mapType = MKMapTypeSatellite;
// mapView.mapType = MKMapTypeHybrid;
}
- (void)viewDidUnload {
self.mapView = nil;
self.progressBar = nil;
self.progressLabel = nil;
self.button = nil;
}
- (void)dealloc {
[mapView release];
[progressBar release];
[progressLabel release];
[button release];
[address release];
[super dealloc];
}
#pragma mark -
#pragma mark CLLocationManagerDelegate Methods
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if ([newLocation.timestamp timeIntervalSince1970] < [NSDate timeIntervalSinceReferenceDate] - 60)
return;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(newLocation.coordinate, 2000, 2000);
MKCoordinateRegion adjustedRegion = [mapView regionThatFits:viewRegion];
[mapView setRegion:adjustedRegion animated:YES];
manager.delegate = nil;
[manager stopUpdatingLocation];
[manager autorelease];
progressBar.progress = .25;
progressLabel.text = NSLocalizedString(#"Reverse Geocoding Location", #"Reverse Geocoding Location");
MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate];
geocoder.delegate = self;
[geocoder start];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
NSString *errorType = (error.code == kCLErrorDenied) ?
NSLocalizedString(#"Access Denied", #"Access Denied") :
NSLocalizedString(#"Unknown Error", #"Unknown Error");
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"Error getting Location", #"Error getting Location")
message:errorType
delegate:self
cancelButtonTitle:NSLocalizedString(#"Okay", #"Okay")
otherButtonTitles:nil];
[alert show];
[alert release];
[manager release];
}
#pragma mark -
#pragma mark Alert View Delegate Methods
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
progressBar.hidden = YES;
progressLabel.text = #"";
}
#pragma mark -
#pragma mark Reverse Geocoder Delegate Methods
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"Error translating coordinates into location", #"Error translating coordinates into location")
message:NSLocalizedString(#"Geocoder did not recognize coordinates", #"Geocoder did not recognize coordinates")
delegate:self
cancelButtonTitle:NSLocalizedString(#"Okay", #"Okay")
otherButtonTitles:nil];
[alert show];
[alert release];
geocoder.delegate = nil;
[geocoder autorelease];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
progressBar.progress = 0.5;
progressLabel.text = NSLocalizedString(#"Location Determined", #"Location Determined");
MapLocation *annotation = [[MapLocation alloc] init];
annotation.streetAddress = placemark.thoroughfare;
annotation.city = placemark.locality;
annotation.state = placemark.administrativeArea;
annotation.zip = placemark.postalCode;
annotation.coordinate = geocoder.coordinate;
NSString *firstTwo = [placemark.thoroughfare stringByAppendingFormat:#" %#",placemark.locality];
NSString *firstThree = [firstTwo stringByAppendingFormat:#", %#",placemark.administrativeArea];
NSString *makeAddress = [firstThree stringByAppendingFormat:#", %#",placemark.postalCode];
address = makeAddress;
NSLog(#"%#", address);
[mapView addAnnotation:annotation];
[annotation release];
geocoder.delegate = nil;
[geocoder autorelease];
}
#pragma mark -
#pragma mark Map View Delegate Methods
- (MKAnnotationView *) mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>) annotation {
static NSString *placemarkIdentifier = #"Map Location Identifier";
if ([annotation isKindOfClass:[MapLocation class]]) {
MKPinAnnotationView *annotationView = (MKPinAnnotationView *)[theMapView dequeueReusableAnnotationViewWithIdentifier:placemarkIdentifier];
if (annotationView == nil) {
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:placemarkIdentifier];
}
else
annotationView.annotation = annotation;
annotationView.enabled = YES;
annotationView.animatesDrop = YES;
annotationView.pinColor = MKPinAnnotationColorPurple;
annotationView.canShowCallout = YES;
[self performSelector:#selector(openCallout:) withObject:annotation afterDelay:0.5];
progressBar.progress = 0.75;
progressLabel.text = NSLocalizedString(#"Creating Annotation",#"Creating Annotation");
return annotationView;
}
return nil;
}
- (void)mapViewDidFailLoadingMap:(MKMapView *)theMapView withError:(NSError *)error {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"Error loading map", #"Error loading map")
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:NSLocalizedString(#"Okay", #"Okay")
otherButtonTitles:nil];
[alert show];
[alert release];
}
I'm assuming when you say "Geocoder", you actually mean the MKReverseGeocoder class. The Reverse Geocoder is part of the Mapkit framework, so in order to use it, you must include it to the file in which you are using it. However, you do not need to add an actual MapView or anything, you can just get the information that the reverse geocoder gives you and pass it on to your server however you want. I hope this answers your question.
Is it possible to use the MKMapView's own location manager to return the users current location to pass into a webservice?
I have mapView.showsUserLocation=YES; and this does return a valid blue dot at my location, but in the simulator, its Cupertino - which is fine, but when i look at
mapView.userLocation.coordinate.latitude, its equal to 180, whereas a CLLocationManager returns the correct one, 37.3317.
I want to avoid having multiple location managers for my three tabs, so using the mapViews own would be helpful.
Thanks.
You can get the user location from the MKMapView. You are just missing a property in your retrieval of it. It should be:
mapView.userLocation.location.coordinate.latitude;
userLocation only stores a CLLocation location attribute and a BOOL updating attribute. You must go to the location attribute to get coordinates.
-Drew
EDIT: The MKMapView's userLocation does not update until the map has finished loading, and checking too early will return zeros. To avoid this, I suggest using the MKMapViewDelegate method
-(void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation.
So, to use a unique CLLocateManager, you can create a class to be the delegate for all you maps., so, instead of doing:
self.locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
Do something like:
self.locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = mySharedDelegate;
Where mySharedDelegate is your class with all the CLLocationManager delegate methods.
You can only get a valid coordinate for the userLocation, after the first calling of - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
When this method is called it is because the GPS has found the new location and so the blue dot will be moved to there and the userLocation will have the new coordinate.
Use the following method on your CLLocationManager delegate to log the current location when it is found:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"---------- locationManager didUpdateToLocation");
location=newLocation.coordinate;
NSLog(#"Location after calibration, user location (%f, %f)", _mapView.userLocation.coordinate.latitude, _mapView.userLocation.coordinate.longitude);
}
Have you got the idea?
Cheers,
VFN
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation
{
NSLog(#"welcome into the map view annotation");
// if it's the user location, just return nil.
if ([annotation isKindOfClass:[MyMapannotation class]])
{
MyMapannotation *annotation12=(MyMapannotation *)annotation;
// try to dequeue an existing pin view first
static NSString* AnnotationIdentifier = #"AnnotationIdentifier";
MKPinAnnotationView* pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:AnnotationIdentifier] ;
pinView.animatesDrop=YES;
pinView.canShowCallout=YES;
pinView.pinColor=MKPinAnnotationColorPurple;
pinView.tag=annotation12.tag;
UIButton* rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
[rightButton setTitle:annotation.title forState:UIControlStateNormal];
rightButton.tag=annotation12.tag;
[rightButton addTarget:self
action:#selector(showDetails:)
forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
UIImageView *profileIconView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"artpin"]];
pinView.image = profileIconView.image;
return pinView;
}
else
return nil;
}
-(IBAction)showDetails:(id)sender
{
UIButton *btn=(UIButton *)sender;
}
-(void)Load_mapview
{
for (int i=0; i<[arr_nearby count]; i++)
{
NSNumber *latitude = [[[[arr_nearby objectAtIndex:i] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lat"];
NSNumber *longitude = [[[[arr_nearby objectAtIndex:i] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lng"];
NSString *title = [[arr_nearby objectAtIndex:i] valueForKey:#"name"];
//Create coordinates from the latitude and longitude values
CLLocationCoordinate2D coord;
coord.latitude = latitude.doubleValue;
coord.longitude = longitude.doubleValue;
MyMapannotation *annotation = [[MyMapannotation alloc] initWithTitle:title AndCoordinate:coord andtag:i];
[_map_nearby addAnnotation:annotation];
// [annotations addObject:annotation];
}
[self zoomToLocation];
}
-(void)zoomToLocation
{
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = [[[[[arr_nearby objectAtIndex:0] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lat"] floatValue];
zoomLocation.longitude= [[[[[arr_nearby objectAtIndex:0] valueForKey:#"geometry"] valueForKey:#"location"] valueForKey:#"lng"] floatValue];
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 7.5*5,7.5*5);
[_map_nearby setRegion:viewRegion animated:YES];
[_map_nearby regionThatFits:viewRegion];
}
//
// MyMapannotation.h
// IOS_Googgle
//
// Created by Vivek Chauhan on 27/06/16.
// Copyright (c) 2016 anand. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface MyMapannotation : NSObject <MKAnnotation>
#property (nonatomic,copy) NSString *title;
#property (nonatomic,assign) int tag;
#property (nonatomic, readonly) CLLocationCoordinate2D coordinate;
-(id) initWithTitle:(NSString *) title AndCoordinate:(CLLocationCoordinate2D)coordinate andtag:(int)tagofbutton;
#end
//
// MyMapannotation.m
// IOS_Googgle
//
// Created by Vivek Chauhan on 27/06/16.
// Copyright (c) 2016 anand. All rights reserved.
//
#import "MyMapannotation.h"
#implementation MyMapannotation
#synthesize coordinate=_coordinate;
#synthesize title=_title;
#synthesize tag=_tag;
-(id) initWithTitle:(NSString *) title AndCoordinate:(CLLocationCoordinate2D)coordinate andtag:(int)tagofbutton
{
self = [super init];
_title = title;
_coordinate = coordinate;
_tag=tagofbutton;
return self;
}
#end