I have MapView that shows two points on a map with a route. When I zoom into the map, after I release, the map zooms back out.
I have zoomEnabled and scrollEnabled all set to yes in Code and on the InterfaceBuilder
#interface MapViewController () <UIApplicationDelegate, MKMapViewDelegate,CLLocationManagerDelegate> {
CLLocationManager * locationManager;
CLPlacemark * pmDesination;
CLLocation * currentLocation;
MyAnnotation * destinationAnn;
MKPolyline *_routeOverlay;
MKRoute *_currentRoute;
}
#end
#implementation MapViewController
const static int TYPE_STATUS_PICKUP = 0;
const static int TYPE_STATUS_DROPOFF = 1;
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[self stopLocationServices];
}
- (void) viewDidLoad {
[super viewDidLoad];
self.mapView.delegate = self;
self.mapView.zoomEnabled = YES;
self.mapView.scrollEnabled = YES;
[self startLocationServices];
//Show points on map
[self addressSearch:self.pickupLocation type:TYPE_STATUS_PICKUP];
[self addressSearch:self.dropoffLocation type:TYPE_STATUS_DROPOFF];
}
- (void) mapViewDidFinishLoadingMap:(MKMapView *)mapView {
[self showRoute];
NSMutableArray * pins = [[NSMutableArray alloc] init];
if (destinationAnn != nil) {
[pins addObject:destinationAnn];
}
if ([self getCurrentLocationAnnotation] != nil) {
[pins addObject:[self getCurrentLocationAnnotation]];
}
if (pins.count > 0) {
[_mapView showAnnotations:pins animated:YES];
}
}
#pragma mapping methods
- (void) addressSearch:(NSMutableDictionary *)pinLocation type:(int)type {
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder geocodeAddressString:pinLocation[#"address"] completionHandler:^(NSArray<CLPlacemark *> * _Nullable placemarks, NSError * _Nullable error) {
if (error) {
//ERROR LOOKING UP ADDRESS
} else {
CLPlacemark * pm = [placemarks lastObject];
location.latitude = pm.location.coordinate.latitude;
location.longitude = pm.location.coordinate.longitude;
[ann setCoordinate:location];
ann.title = [pinLocation objectForKey:#"title"];
ann.subtitle = [pinLocation objectForKey:#"address"];
if (type == _toLocation) {
destinationAnn = ann;
}
[self.mapView addAnnotation:ann];
}
}];
}
#pragma mark - SHOW ROUTE
- (void) showRoute {
MKDirectionsRequest *directionsRequest = [MKDirectionsRequest new];
MKMapItem *source = [MKMapItem mapItemForCurrentLocation];
// Make the destination
CLLocationCoordinate2D destinationCoords = CLLocationCoordinate2DMake(destinationAnn.coordinate.latitude, destinationAnn.coordinate.longitude);
MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoords addressDictionary:nil];
MKMapItem *destination = [[MKMapItem alloc] initWithPlacemark:destinationPlacemark];
// Set the source and destination on the request
[directionsRequest setSource:source];
[directionsRequest setDestination:destination];
MKDirections *directions = [[MKDirections alloc] initWithRequest:directionsRequest];
[directions calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error) {
NSLog(#"There was an error getting your directions: %#", error.localizedDescription);
return;
}
_currentRoute = [response.routes firstObject];
[self plotRouteOnMap:_currentRoute];
}];
}
- (void)plotRouteOnMap:(MKRoute *)route
{
if(_routeOverlay) {
[self.mapView removeOverlay:_routeOverlay];
}
// Update the ivar
_routeOverlay = route.polyline;
// Add it to the map
[self.mapView addOverlay:_routeOverlay];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = _toLocation ? [UIColor orangeColor] : [UIColor greenColor];
renderer.lineWidth = 4.0;
return renderer;
}
// DELGATE THAT RUNS TO SHOW CURRENT USER LOCATION
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(nonnull NSError *)error {
NSLog(#"Location Services Error: %#", [error description]);
[[LoggingManager sharedReporting] addReportToLog:[NSString stringWithFormat:#"Mapping: locationManager:didFailWithError: %#",[error description] ]];
}
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations: (NSArray *)locations {
currentLocation = [locations lastObject];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
currentLocation = newLocation;
}
#pragma mark - GET TO AND CURRENT POINTS
- (NSString*) getDestination {
NSDictionary * desDict = _toLocation ? self.dropoffLocation : self.pickupLocation;
NSString * address = #"";
if ([[desDict objectForKey:#"lat"] length] > 0 && [[desDict objectForKey:#"lon"] length] > 0) {
address = [NSString stringWithFormat:#"%#,%#",[desDict objectForKey:#"lat"], [desDict objectForKey:#"lon"]];
} else if ([desDict[#"address"] length] > 0 && [desDict[#"address"] rangeOfString:#"{"].location == NSNotFound) {
address = [desDict objectForKey:#"address"];
} else {
address = #"NULL";
}
return address;
}
- (NSString*) getCurrentLocation {
return [NSString stringWithFormat:#"%f,%f", currentLocation.coordinate.latitude, currentLocation.coordinate.longitude];
}
- (MyAnnotation*) getCurrentLocationAnnotation {
MyAnnotation * ann = [[MyAnnotation alloc] init];
CLLocationCoordinate2D location = CLLocationCoordinate2DMake(currentLocation.coordinate.latitude, currentLocation.coordinate.longitude);
[ann setCoordinate:location];
ann.title = #"My Current Location";
ann.subtitle = #"";
return ann;
}
#end
The problem is that you are setting the map's visible region by calling showAnnotations. This conflicts with the user zooming.
Related
I'm trying to display multiple arrays of locations on my mapView with the below code (Restaurants, Parks, Meet Ups & Stores). When I open the app, not all addresses inside the arrays are displayed on my mapView (even though all data is returned) - e.g. sometimes only 'Stores' and 'Parks' arrays of annotations will show up on my map, but Restaurants aren't visible (even though data for all arrays is returned successfully). If I close out and reopen the app, sometimes Parks will show on the map, but nothing else. Any idea why this happens, and how I can fix it? Code updated below. Been at this forever!
Note: ParksAnnotation, RestAnnotation, meetupAnn, & StoreAnnotation are all MKPointAnnotation classes.
UPDATE (10/13/2020): I tried logging 'placemarks' under the block of code that retrieves and geocodes my 'Stores' coordinates. It appears as though self.storeData is populated, as is the created NSDictionary storeFields. That said, when I log 'placemarks', it isn't returning any coordinates, even though storeFields[#"address"] is populated. The other blocks of code seem to be doing their job just fine (ie. retrieving Meet Ups and retrieving Parks). So Meet Ups, Restaurants and Parks annotations appear fine, but all Stores annotations aren't populated. This happens to at least one type of annotation (sometimes it's Stores that's missing, other times it's Parks) at random when I launch the app. I can't for the life of me sort out why this is happening.
See below code:
MapViewController.m
#import "StoreAnnotation.h"
#import "ParksAnnotation.h"
#import "RestAnnotation.h"
#import "meetupAnn.h"
#interface MapViewController ()
#end
#implementation MapViewController
-(void)viewWillAppear:(BOOL)animated {
NSMutableDictionary *viewParamsallUsers1 = [NSMutableDictionary new];
[viewParamsallUsers1 setValue:#"hosted_meet_ups" forKey:#"view_name"];
[DIOSView viewGet:viewParamsallUsers1 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.meetUps = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *allMeetups in self.meetUps) {
NSString *location = allMeetups[#"where"];
NSString *userNames = allMeetups[#"node_title"];
NSString *userBio = allMeetups[#"body"];
self.alertMessage = [allMeetups[#"node_title"] mutableCopy];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
meetupAnn *meet = [[meetupAnn alloc] init];
meet.coordinate = placemark.coordinate;
meet.title = userNames;
meet.subtitle = userBio;
meet.index = index; // Store index here.
[self.mapView addAnnotation:meet];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
/// GRAB ALL RESTAURANT LOCATIONS ///
NSMutableDictionary *viewParams6 = [NSMutableDictionary new];
[viewParams6 setValue:#"restaurants" forKey:#"view_name"];
[DIOSView viewGet:viewParams6 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.neighbourhoodData = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *multiplelocationsFriend in self.neighbourhoodData) {
NSString *location = multiplelocationsFriend[#"address"];
NSString *userNames = multiplelocationsFriend[#"node_title"];
NSString *ampRemoved = [userNames stringByReplacingOccurrencesOfString:#"amp;" withString:#""];
NSString *userBio = multiplelocationsFriend[#"body"];
self.x3 = multiplelocationsFriend[#"x3"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
RestAnnotation *point1 = [[RestAnnotation alloc] init];
point1.coordinate = placemark.coordinate;
point1.title = ampRemoved;
point1.subtitle = userBio;
point1.index = index; // Store index here.
[self.mapView addAnnotation:point1];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
NSString *test = self.areaName;
NSLog(#"SHOW TEST %#", test);
/// GRAB ALL STORE LOCATIONS ///
NSMutableDictionary *viewParams7 = [NSMutableDictionary new];
[viewParams7 setValue:#"stores" forKey:#"view_name"];
[DIOSView viewGet:viewParams7 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.storesData = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *storeFields in self.storesData) {
NSString *location = storeFields[#"address"];
NSString *userNames = storeFields[#"node_title"];
NSString *ampRemoved = [userNames stringByReplacingOccurrencesOfString:#"amp;" withString:#""];
NSString *userBio = storeFields[#"body"];
self.x3 = storeFields[#"x3"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
StoreAnnotation *point2 = [[StoreAnnotation alloc] init];
point2.coordinate = placemark.coordinate;
point2.title = ampRemoved;
point2.subtitle = userBio;
point2.index = index; // Store index here.
[self.mapView addAnnotation:point2];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
/// GRAB ALL PARKS LOCATIONS ///
NSMutableDictionary *viewParams8 = [NSMutableDictionary new];
[viewParams8 setValue:#"parks" forKey:#"view_name"];
[DIOSView viewGet:viewParams8 success:^(AFHTTPRequestOperation *operation, id responseObject) {
self.parksData = [responseObject mutableCopy];
int index = 0;
for (NSMutableDictionary *parkFields in self.parksData) {
// NSLog(#"WHAT IS IN FRIENDS %#", self.friendData);
NSString *location = parkFields[#"address"];
NSString *userNames = parkFields[#"node_title"];
NSString *ampRemoved = [userNames stringByReplacingOccurrencesOfString:#"amp;" withString:#""];
NSString *userBio = parkFields[#"body"];
self.x3 = parkFields[#"x3"];
CLGeocoder *geocoderFriend = [[CLGeocoder alloc] init];
[geocoderFriend geocodeAddressString:location
completionHandler:^(NSArray* placemarks, NSError* error){
if (placemarks && placemarks.count > 0) {
CLPlacemark *topResult = [placemarks objectAtIndex:0];
MKPlacemark *placemark = [[MKPlacemark alloc] initWithPlacemark:topResult];
MKCoordinateRegion region = self.mapView.region;
region.span.longitudeDelta /= 150.0;
region.span.latitudeDelta /= 150.0;
ParksAnnotation *point3 = [[ParksAnnotation alloc] init];
point3.coordinate = placemark.coordinate;
point3.title = ampRemoved;
point3.subtitle = userBio;
point3.index = index; // Store index here.
[self.mapView addAnnotation:point3];
}
}
];
index = index + 1;
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", [error localizedDescription]);
}];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
MKCoordinateRegion mapRegion;
mapRegion.center = mapView.userLocation.coordinate;
mapRegion.span.latitudeDelta = 0.5;
mapRegion.span.longitudeDelta = 0.5;
[mapView setRegion:mapRegion animated: YES];
[self.locationManager stopUpdatingLocation];
self.locationManager = nil;
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 8000, 8000);
[mapView setRegion:[mapView regionThatFits:region] animated:YES];
[mapView addAnnotations:[mapView annotations]];
});
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation{
if([annotation isKindOfClass:[StoreAnnotation class]]) {
static NSString *identifier = #"stores";
MKAnnotationView *storesView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(storesView == nil) {
storesView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
storesView.displayPriority = MKFeatureDisplayPriorityRequired;
storesView.canShowCallout = YES;
storesView.image = [UIImage imageNamed:#"storeann4.png"];
}
else {
storesView.annotation = annotation;
}
return storesView;
}
if([annotation isKindOfClass:[meetupAnn class]]) {
static NSString *identifier = #"meetUps";
MKAnnotationView *pulsingView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(pulsingView == nil) {
pulsingView.displayPriority = MKFeatureDisplayPriorityRequired;
pulsingView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pulsingView.image = [UIImage imageNamed:#"meetupbeacon.png"];
pulsingView.canShowCallout = YES;
}
else {
pulsingView.annotation = annotation;
}
return pulsingView;
}
if([annotation isKindOfClass:[ParksAnnotation class]]) {
static NSString *identifier = #"parks";
MKAnnotationView *parksView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(parksView == nil) {
parksView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
parksView.displayPriority = MKFeatureDisplayPriorityRequired;
parksView.image = [UIImage imageNamed:#"parksann.png"];
parksView.canShowCallout = YES;
}
else {
parksView.annotation = annotation;
}
return parksView;
}
if([annotation isKindOfClass:[RestAnnotation class]]) {
static NSString *identifier = #"rests";
MKAnnotationView *restView = (MKAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(restView == nil) {
restView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
restView.displayPriority = MKFeatureDisplayPriorityRequired;
restView.image = [UIImage imageNamed:#"restann.png"];
restView.canShowCallout = YES;
}
else {
restView.annotation = annotation;
}
return restView;
}
As Ramis said, the problem is that you're setting the displayPriority before you even instantiate the pulsingView. Thus, the MKAnnotationView you subsequently instantiate never got its displayPriority set.
That having been said, I'd suggest a slightly different implementation, though. Specifically, I'd move the configuration of the annotation view into its own subclass, rather than cluttering the view controller with this sort of code:
#interface MeetUpAnnotationView: MKAnnotationView
#end
#implementation MeetUpAnnotationView
- (instancetype)initWithAnnotation:(id<MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self) {
self.displayPriority = MKFeatureDisplayPriorityRequired;
self.canShowCallout = YES;
self.image = [UIImage imageNamed:#"meetupbeacon.png"];
}
return self;
}
- (void)setAnnotation:(id<MKAnnotation>)annotation {
[super setAnnotation:annotation];
self.displayPriority = MKFeatureDisplayPriorityRequired;
}
#end
Then, if targeting iOS 11 or later, your view controller's viewDidLoad should register that subclass.
Now, if this is the only annotation view that you’re showing in iOS 11, you don't need a viewForAnnotation at all and can just register your default annotation view:
[self.mapView registerClass:[MeetUpAnnotationView class] forAnnotationViewWithReuseIdentifier:MKMapViewDefaultAnnotationViewReuseIdentifier];
And having registered the annotation view class, you're done. No viewForAnnotation is needed or desired.
The only time you have to implement viewForAnnotation in iOS 11 and later is if you have multiple custom annotation view types on your map. In that case, you'd register them:
[self.mapView registerClass:[MeetUpAnnotationView class] forAnnotationViewWithReuseIdentifier:meetupIdentifier];
[self.mapView registerClass:[SomeOtherAnnotationView class] forAnnotationViewWithReuseIdentifier:someOtherIdentifier];
And then use dequeueReusableAnnotationViewWithIdentifier:forAnnotation: in your viewForAnnotation:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MeetupAnn class]]) {
return [mapView dequeueReusableAnnotationViewWithIdentifier:meetupIdentifier forAnnotation:annotation];
}
if ([annotation isKindOfClass:[SomeOtherAnnotation class]]) {
return [mapView dequeueReusableAnnotationViewWithIdentifier:someOtherIdentifier forAnnotation:annotation];
}
...
return nil;
}
As you can see, in iOS 11 (especially when you have only one annotation view type), the code is greatly simplified.
But if you need to support older iOS versions, you can't register the identifier and you have to use the older dequeueReusableAnnotationViewWithIdentifier:, but I'd still let the annotation view subclass take care of configuring itself. But, a more subtle problem in your code is that you are not setting the annotation in an else clause, so make sure to do that, e.g.:
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
if ([annotation isKindOfClass:[MeetupAnn class]]) {
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:meetupIdentifier];
if (!annotationView) {
annotationView = [[MeetUpAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:meetupIdentifier];
} else {
annotationView.annotation = annotation;
}
return annotationView;
}
return nil;
}
You should check if some of your geocoding requests are failing inconsistently.
CLGeocoder rate limits your requests and if you do too many requests in a short time, you'll receive an error. https://developer.apple.com/documentation/corelocation/clgeocoder/1423509-geocodeaddressstring?language=objc
Check if you are getting any reason for failure inside NSError* error inside the completionHandler block.
As many times as it fails, you should see as many less number of annotations on the MapView because it is not entering the following code path.
if (placemarks && placemarks.count > 0) {
// Not entering here
}
if (nil != error) {
// Could land here
}
The only other reason would be not properly calculating map region to show all annotations in screen. Make sure you are calculating/adjusting the region correctly upon each annotation being added to the mapView.
// Define these variables globally in the view controller
CLLocationDegrees minLatitude = 90.0;
CLLocationDegrees maxLatitude = -90.0;
CLLocationDegrees minLongitude = 180.0;
CLLocationDegrees maxLongitude = -180.0;
// Call following method every time a new annotation needs to be added to the mapView
-(void)addAnnotation:(id<MKAnnotation>)annotation toMapView:(MKMapView*)mapView {
// Add the annotation to map
[mapView addAnnotation:annotation];
// Set the map region to make it visible along with all other annotations
CLLocationDegrees latitude = annotation.coordinate.latitude;
CLLocationDegrees longitude = annotation.coordinate.longitude;
minLatitude = min(minLatitude, latitude);
maxLatitude = max(maxLatitude, latitude);
minLongitude = min(minLongitude, longitude);
maxLongitude = max(maxLongitude, longitude);
CLLocationDegrees latitudeDelta = (maxLatitude - minLatitude);
CLLocationDegrees longitudeDelta = (maxLongitude - minLongitude);
CLLocationDegrees midLatitude = (maxLatitude - latitudeDelta/2);
CLLocationDegrees midLongitude = (maxLongitude - longitudeDelta/2);
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(midLatitude, midLongitude);
MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
MKCoordinateRegion region = MKCoordinateRegionMake(center, span);
if (CLLocationCoordinate2DIsValid(center)) {
[mapView setRegion:region animated:YES];
}
}
You are assigning MKFeatureDisplayPriorityRequired to empty object. Try to assign display priority in two case:
When pulsingView is not nil.
After pulsingView allocated.
if([annotation isKindOfClass:[meetupAnn class]]) {
static NSString *identifier = #"currentLocation";
MKAnnotationView *pulsingView = (MKAnnotationView *)[self.friendsMapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(pulsingView == nil) {
pulsingView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
pulsingView.displayPriority = MKFeatureDisplayPriorityRequired;
pulsingView.canShowCallout = YES;
pulsingView.image = [UIImage imageNamed:#"meetupbeacon.png"];
NSLog(#"Location Returned");
} else {
pulsingView.displayPriority = MKFeatureDisplayPriorityRequired;
// TODO: Do map pin initial setup.
}
}
I am stuck with a problem on the mapView. I am really sorry to ask this question but I have searched for almost one day to look into this issue but I don't find a solution to fix it.
#interface MapViewController ()<CLLocationManagerDelegate, MKMapViewDelegate, UITextFieldDelegate, CheckInDelegate, NotificationsViewControllerDelegate, ReportVCDelegate, TutorialViewControllerDelegate> {
CLLocationManager *locationManager;
NSTimer *refreshTimer;
int rangeValue;
CheckInViewController *checkInVC;
TutorialViewController *tutorialVC1;
TutorialViewController *tutorialVC2;
UIImageView *imgAvatar;
NSArray *markers;
}
#property (weak, nonatomic) IBOutlet UIView *viewSearch;
#property (weak, nonatomic) IBOutlet RateView *viewRate;
#property (weak, nonatomic) IBOutlet UIView *viewBottom;
#property (weak, nonatomic) IBOutlet UILabel *lblUsername;
#property (weak, nonatomic) IBOutlet UITextField *txtSearch;
#property (weak, nonatomic) IBOutlet UIBarButtonItem *btnNotifications;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomSpace;
#property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomHeight;
#property (weak, nonatomic) IBOutlet UIButton *btnBottom;
#property (weak, nonatomic) IBOutlet HandsawayMapView *mapView;
#property (weak, nonatomic) IBOutlet UIView *mapViewContainer;
#property (strong, nonatomic) MKPlacemark *searchMarker;
#property (strong, nonatomic) MKUserLocation *myMarker;
#property (weak, nonatomic) MapToolbarViewController *mapToolbar;
#property (strong, atomic) NSArray *allMapMarkers;
#property (strong, nonatomic) NSNumber *aggressionIdToCenter;
#end
#implementation MapViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
// [[UserModel sharedModel] setUserHome:#(1)];
rangeValue = 300;
self.viewSearch.layer.masksToBounds = NO;
self.viewSearch.layer.shadowRadius = 0.5f;
self.viewSearch.layer.shadowColor = [UIColor blackColor].CGColor;
self.viewSearch.layer.shadowOffset = CGSizeMake(0.0f, 0.5f);
self.viewSearch.layer.shadowOpacity = 0.5f;
self.viewRate.starCount = 4;
self.viewRate.step = 1.0f;
self.viewRate.starNormalColor = UIColorFromRGB(0xD8D8D8);
self.viewRate.starFillColor = UIColorFromRGB(0xFF5B59);
self.viewRate.rating = 3.0f;
self.viewRate.starSize = 20.0f;
self.viewRate.padding = 8.0f;
locationManager = [[CLLocationManager alloc] init];
[locationManager requestWhenInUseAuthorization];
locationManager.delegate = self;
[DbHelper saveActivationWithNumer:#(1)];
imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]];
}];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
NSNumber *agressionID = [[NSUserDefaults standardUserDefaults] valueForKey:#"aggression_id"];
if (agressionID && agressionID != 0)
{
self.aggressionIdToCenter = agressionID;
[[NSUserDefaults standardUserDefaults] setValue:0 forKey:#"aggression_id"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
if (self.aggressionIdToCenter != nil) {
[self centerOnAggressionWithId:self.aggressionIdToCenter];
self.aggressionIdToCenter = nil;
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[locationManager stopUpdatingLocation];
didSetLocation = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (UIView*)locationPin {
User *user = [DbHelper getCurrentUser];
UIImage *pin = [UIImage imageNamed:#"marker-person"];
if([user.isCurrent boolValue]) {
pin = [UIImage imageNamed:#"my-pin"];
}
UIImageView *pinImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 39, 48)];
[pinImageView setImage:pin];
UIView *markerContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 39, 48)];
[markerContainer addSubview:pinImageView];
imgAvatar = [[UIImageView alloc] initWithFrame:CGRectMake(4.5, 4.5, 30, 30)];
[imgAvatar setContentMode:UIViewContentModeScaleAspectFill];
imgAvatar.layer.cornerRadius = 15;
imgAvatar.clipsToBounds = YES;
[markerContainer addSubview:imgAvatar];
if([user.isPictureHidden boolValue]) {
[imgAvatar setImage:[user avatarPlaceholder]];
}
else {
[imgAvatar setImageWithURL:[NSURL URLWithString:user.pictureURL] placeholderImage:[user avatarPlaceholder]];
}
[pinImageView setBackgroundColor:[UIColor clearColor]];
[imgAvatar setBackgroundColor:[UIColor clearColor]];
[markerContainer setBackgroundColor:[UIColor clearColor]];
return markerContainer;
}
- (void)ckeckUserImage
{
User *user = [DbHelper getCurrentUser];
if([user.isPictureHidden boolValue]) {
[imgAvatar setImage:[user avatarPlaceholder]];
}
else {
[imgAvatar setImageWithURL:[NSURL URLWithString:user.pictureURL] placeholderImage:[user avatarPlaceholder]];
}
if (self.mapToolbar.currentUser)
{
[self.mapToolbar setCurrentUser];
}
}
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
if([segue.identifier isEqualToString:#"PresentInfo"]) {
self.mapToolbar = segue.destinationViewController;
self.mapToolbar.height = self.bottomHeight;
self.mapToolbar.masterVC = self;
} else if ([segue.identifier isEqualToString:#"NotificationsSegue"] && [segue.destinationViewController isKindOfClass:[NotificationsViewController class]]) {
NotificationsViewController *destination = (NotificationsViewController *)segue.destinationViewController;
destination.delegate = self;
}
else if([segue.identifier isEqualToString:#"ActionSheetMap"]) {
self.VCactionSheetMap = segue.destinationViewController;
self.VCactionSheetMap.delegate = self.mapToolbar;
} else if ([segue.identifier isEqualToString:#"mapToReport"]) {
self.reportVC = (ReportVC *)segue.destinationViewController;
self.reportVC.delegate = self;
}
}
- (IBAction)onMenu:(id)sender {
[self.frostedViewController presentMenuViewController];
}
-(IBAction)onLocate:(id)sender {
self.txtSearch.text = #"";
[self.mapView removeAnnotation:self.searchMarker];
self.searchMarker = nil;
didSetLocation = NO;
}
- (IBAction)onCheckIn:(id)sender {
if([[NSUserDefaults standardUserDefaults] valueForKey:#"tutorials2"]) {
self.btnCheckin.hidden = YES;
checkInVC = [self.storyboard instantiateViewControllerWithIdentifier:#"NewCheckin"];
checkInVC.delegate = self;
checkInVC.model = [[CheckInModel alloc] init];
if(_searchMarker != nil) {
checkInVC.model.longitude = (double) _searchMarker.coordinate.longitude;
checkInVC.model.latitude = (double) _searchMarker.coordinate.latitude;
}
else {
checkInVC.model.longitude = (double) locationManager.location.coordinate.longitude;
checkInVC.model.latitude = (double) locationManager.location.coordinate.latitude;
}
if([sender isKindOfClass:[NSNumber class]]) {
checkInVC.agressionId = sender;
}
UIWindow *currentWindow = [UIApplication sharedApplication].keyWindow;
[currentWindow addSubview:checkInVC.view];
}
else {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if(![[NSUserDefaults standardUserDefaults] valueForKey:#"tutorials2"]) {
[self.navigationController setNavigationBarHidden:YES animated:YES];
[self.btnCheckin setAdjustsImageWhenHighlighted:NO];
[self.btnCheckin setUserInteractionEnabled:NO];
UIStoryboard *tutorials = [UIStoryboard storyboardWithName:#"Tutorial" bundle:nil];
tutorialVC2 = (TutorialViewController *)[tutorials instantiateViewControllerWithIdentifier:[NSString stringWithFormat:#"Tutorial%ld", (long)2]];
tutorialVC2.delegate = self;
[[tutorialVC2 view] setFrame:self.view.bounds];
[self.view insertSubview:[tutorialVC2 view] belowSubview:self.btnCheckin];
[[NSUserDefaults standardUserDefaults] setValue:#YES forKey:#"tutorials2"];
}
});
}
}
- (IBAction)onNotifications:(id)sender {
if([[NSUserDefaults standardUserDefaults] valueForKey:#"tutorials1"]) {
[self performSegueWithIdentifier:#"NotificationsSegue" sender:nil];
}
else {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if(![[NSUserDefaults standardUserDefaults] valueForKey:#"tutorials1"]) {
[self.navigationController setNavigationBarHidden:YES animated:YES];
UIStoryboard *tutorials = [UIStoryboard storyboardWithName:#"Tutorial" bundle:nil];
tutorialVC1 = (TutorialViewController *)[tutorials instantiateViewControllerWithIdentifier:[NSString stringWithFormat:#"Tutorial%ld", (long)1]];
tutorialVC1.delegate = self;
[[tutorialVC1 view] setFrame:self.view.bounds];
[self.view addSubview:[tutorialVC1 view]];
[[NSUserDefaults standardUserDefaults] setValue:#YES forKey:#"tutorials1"];
}
});
});
}
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
[manager startUpdatingLocation];
}
BOOL didSetLocation;
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray<CLLocation *> *)locations {
if(locations.count > 0 ) {
CLLocation *aUserLocation = locations[0];
self.myMarker.coordinate = aUserLocation.coordinate;
// if(_myMarker == nil) {
// GMSMarker *marker = [[GMSMarker alloc] init];
// marker.iconView = [[DbHelper getCurrentUser] locationPin];
// marker.map = mapView_;
// _myMarker = marker;
// }
// _myMarker.position = aUserLocation.coordinate;
if(!didSetLocation) {
didSetLocation = YES;
MKCoordinateRegion region;
MKCoordinateSpan span;
span.latitudeDelta = 0.01557113906538632;
span.longitudeDelta = 0.02284631241712987;
CLLocationCoordinate2D location;
location.latitude = aUserLocation.coordinate.latitude;
location.longitude = aUserLocation.coordinate.longitude;
region.span = span;
region.center = location;
[self.mapView setRegion:region animated:YES];
// [APICLIENT locateUserWithCoordinates:location
// completion:^(NSDictionary *result) {
//
// } error:^{
//
// }];
}
}
}
#pragma mark - Bottom bar
BOOL isBottomBarShown = YES;
}
#pragma mark - MKMapViewDelegate
- (void)mapView:(MKMapView *)mapView regionWillChangeAnimated:(BOOL)animated {
// NSLog(#"longitured : %#, lattitude: %#", #(mapView.region.span.longitudeDelta), #(mapView.region.span.latitudeDelta));
[self hideBottomView];
[refreshTimer invalidate];
refreshTimer = [NSTimer scheduledTimerWithTimeInterval:0.8
target:self
selector:#selector(refreshMapMarkersWithCoordinates:)
userInfo:#{#"longitude" : #(mapView.region.center.longitude), #"latitude" : #(mapView.region.center.latitude), #"range" : #(rangeValue)}
repeats:NO];
}
- (nullable MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {
if(![annotation isKindOfClass:[MKPlacemark class]]) {
MKAnnotationView * annotationView = [MKAnnotationView new];
if([annotation isKindOfClass:[MKUserLocation class]]) {
UIView *userView = [self locationPin];
[annotationView setFrame:userView.frame];
[annotationView addSubview:userView];
self.myMarker = annotation;
[self.mapView sendSubviewToBack:annotationView];
}
else {
annotationView.annotation = annotation;
Marker *dbmarker = ((MarkerAnnotation*)annotation).userData;
if(dbmarker.agression != nil) {
[annotationView setImage:[dbmarker markerImage]];
[self.mapView bringSubviewToFront:annotationView];
}
else if(dbmarker.user != nil) {
UIView *userView = [dbmarker userMarkerView];
[annotationView setFrame:userView.frame];
[annotationView addSubview:userView];
[self.mapView bringSubviewToFront:annotationView];
}
}
return annotationView;
}
return nil;
}
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view {
if(view.annotation != self.searchMarker && view.annotation != self.myMarker) {
if([view.annotation isKindOfClass:[MKUserLocation class]]) {
}
else {
[self selectMarker:((MarkerAnnotation*)view.annotation).userData];
}
}
else
{
if (view.annotation == self.myMarker)
{
[self.mapToolbar setCurrentUser];
}
[self showBottomView];
}
}
- (void)mapView:(MKMapView *)mapView didDeselectAnnotationView:(MKAnnotationView *)view {
if(view.annotation != self.searchMarker && view.annotation != self.myMarker) {
if([view.annotation isKindOfClass:[MKUserLocation class]]) {
}
else {
[self hideBottomView];
}
}
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
[APICLIENT locateUserWithCoordinates:userLocation.location.coordinate
completion:^(NSDictionary *result) {
} error:^{
}];
}
#pragma mark - GMSMap delegate
//- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
// [self selectMarker:marker];
// return YES;
//}
- (void)selectMarker:(Marker *)marker {
Marker *dbMarker = marker;
if(dbMarker.agression != nil) {
[APICLIENT getAgressionWithId:dbMarker.agression.webID
completion:^(Marker *newmarker) {
[APICLIENT getUserById:[newmarker.user.webID stringValue]
completion:^(User *result) {
self.mapToolbar.marker = newmarker;
//[self showBottomView];
} error:^{
}];
} error:^{
}];
}
else {
[APICLIENT getUserById:[dbMarker.user.webID stringValue]
completion:^(User *result) {
self.mapToolbar.marker = dbMarker;
[self showBottomView];
} error:^{
}];
}
}
-(void)reloadMarkers {
[APICLIENT getMapMarkersAroundMeWithCoordinates:self.mapView.region.center
range:#(rangeValue)
completion:^(NSArray *result) {
[self updateDistance];
NSArray *oldAnnotations = [self.mapView.annotations filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF.class == %#", [MarkerAnnotation class]]];
oldAnnotations = [oldAnnotations valueForKey:#"userData"];
markers = [Marker MR_findAllWithPredicate:[NSPredicate predicateWithFormat:#"NOT (SELF IN %#)", oldAnnotations]];
//[self.mapView removeAnnotations:self.mapView.annotations];
NSMutableArray *allMapMarkersMutable = [[NSMutableArray alloc] init];
for(Marker *dbmarker in markers) {
MarkerAnnotation *marker = [[MarkerAnnotation alloc] init];
marker.coordinate = CLLocationCoordinate2DMake([dbmarker.latitude doubleValue], [dbmarker.longitude doubleValue]);
marker.userData = dbmarker;
[self.mapView addAnnotation:marker];
[allMapMarkersMutable addObject:marker];
}
self.allMapMarkers = [[allMapMarkersMutable copy] arrayByAddingObjectsFromArray:oldAnnotations];
if(_searchMarker != nil && ![self.mapView.annotations containsObject:_searchMarker]) {
[self.mapView addAnnotation:_searchMarker];
}
if(self.aggressionIdToCenter != nil) {
[self centerOnAggressionWithId:self.aggressionIdToCenter];
self.aggressionIdToCenter = nil;
}
} error:^{
}];
/*NSArray *oldAnnotations = [self.mapView.annotations filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"SELF.class == %#", [MarkerAnnotation class]]];
oldAnnotations = [oldAnnotations valueForKey:#"userData"];
markers = [Marker MR_findAllWithPredicate:[NSPredicate predicateWithFormat:#"NOT (SELF IN %#)", oldAnnotations]];
// [self.mapView removeAnnotations:self.mapView.annotations];
NSMutableArray *allMapMarkersMutable = [[NSMutableArray alloc] init];
for(Marker *dbmarker in markers) {
MarkerAnnotation *marker = [[MarkerAnnotation alloc] init];
marker.coordinate = CLLocationCoordinate2DMake([dbmarker.latitude doubleValue], [dbmarker.longitude doubleValue]);
marker.userData = dbmarker;
[self.mapView addAnnotation:marker];
[allMapMarkersMutable addObject:marker];
}
self.allMapMarkers = [[allMapMarkersMutable copy] arrayByAddingObjectsFromArray:oldAnnotations];
if(_searchMarker != nil && ![self.mapView.annotations containsObject:_searchMarker]) {
[self.mapView addAnnotation:_searchMarker];
}
if(self.aggressionIdToCenter != nil) {
[self centerOnAggressionWithId:self.aggressionIdToCenter];
self.aggressionIdToCenter = nil;
}*/
}
//-(void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
// [self hideBottomView];
//}
#pragma mark - UITextFieldDelegate and place search
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
[self.view endEditing:YES];
MKCoordinateRegion newRegion;
newRegion.center.latitude = locationManager.location.coordinate.latitude;
newRegion.center.longitude = locationManager.location.coordinate.longitude;
// Setup the area spanned by the map region:
// We use the delta values to indicate the desired zoom level of the map,
// (smaller delta values corresponding to a higher zoom level).
// The numbers used here correspond to a roughly 8 mi
// diameter area.
//
newRegion.span.latitudeDelta = 0.112872;
newRegion.span.longitudeDelta = 0.109863;
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = textField.text;
request.region = newRegion;
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
MKLocalSearchCompletionHandler completionHandler = ^(MKLocalSearchResponse *response, NSError *error) {
if (error != nil) {
// NSString *errorStr = [[error userInfo] valueForKey:NSLocalizedDescriptionKey];
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Could not find places"
// message:errorStr
// delegate:nil
// cancelButtonTitle:#"OK"
// otherButtonTitles:nil];
// [alert show];
} else {
NSArray<MKMapItem *> *mapItems = [response mapItems];
if(mapItems.count > 0) {
MKCoordinateRegion boundingRegion = response.boundingRegion;
MKMapItem *item = mapItems[0];
self.searchMarker = item.placemark;
[self.mapView addAnnotation:item.placemark];
[self.mapView setRegion:boundingRegion animated:YES];
}
}
};
[localSearch startWithCompletionHandler:completionHandler];
double radians(double degrees) {
return degrees * M_PI / 180.0;
}
double degrees(double radians) {
return radians * 180.0 / M_PI;
}
const CLLocationDegrees kLatLonEarthRadius = 6371.0;
CLLocationCoordinate2D LatLonDestPoint(CLLocationCoordinate2D origin, double bearing, CLLocationDistance distance) {
double brng = radians(bearing);
double lat1 = radians(origin.latitude);
double lon1 = radians(origin.longitude);
CLLocationDegrees lat2 = asin(sin(lat1) * cos(distance / kLatLonEarthRadius) +
cos(lat1) * sin(distance / kLatLonEarthRadius) * cos(brng));
CLLocationDegrees lon2 = lon1 + atan2(sin(brng) * sinf(distance / kLatLonEarthRadius) * cos(lat1),
cosf(distance / kLatLonEarthRadius) - sin(lat1) * sin(lat2));
lon2 = fmod(lon2 + M_PI, 2.0 * M_PI) - M_PI;
CLLocationCoordinate2D coordinate;
if (! (isnan(lat2) || isnan(lon2))) {
coordinate.latitude = degrees(lat2);
coordinate.longitude = degrees(lon2);
}
return coordinate;
}
#pragma mark - CheckInDelegate
- (void)willRemoveCheckinView {
[[UIApplication sharedApplication] setStatusBarHidden:NO
withAnimation:UIStatusBarAnimationSlide];
[self.navigationController setNavigationBarHidden:NO
animated:YES];
}
The problem is you are adding marker in MKLocalSearchCompletionHandler, so remove below line from MKLocalSearchCompletionHandler will solved your issue.
[self.mapView addAnnotation:item.placemark];
You can remove all annotation pins from MKMapView by using following code
for (int i =0; i < [_mapView.annotations count]; i++) {
if ([[_mapView.annotations objectAtIndex:i] isKindOfClass:[YOURANNOTATIONCLASS class]]) {
[_mapView removeAnnotation:[_mapView.annotations objectAtIndex:i]];
}
}
If you want to remove Annotation while search then remove bellow code in textFieldShouldReturn method.
Find method:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
}
Then Comment or Remove bellow code
MKLocalSearchRequest *request = [[MKLocalSearchRequest alloc] init];
request.naturalLanguageQuery = textField.text;
request.region = newRegion;
MKLocalSearch *localSearch = [[MKLocalSearch alloc] initWithRequest:request];
MKLocalSearchCompletionHandler completionHandler = ^(MKLocalSearchResponse *response, NSError *error) {
if (error != nil) {
// NSString *errorStr = [[error userInfo] valueForKey:NSLocalizedDescriptionKey];
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Could not find places"
// message:errorStr
// delegate:nil
// cancelButtonTitle:#"OK"
// otherButtonTitles:nil];
// [alert show];
} else {
NSArray<MKMapItem *> *mapItems = [response mapItems];
if(mapItems.count > 0) {
MKCoordinateRegion boundingRegion = response.boundingRegion;
MKMapItem *item = mapItems[0];
self.searchMarker = item.placemark;
[self.mapView addAnnotation:item.placemark];
[self.mapView setRegion:boundingRegion animated:YES];
}
}
};
Hope it will help you
I am working on one app, I need to show route directions between two coordinates. I have used MKDirections and have passed two coordinates as source and destination, however on mapView its not showing any route or drawing any polyline. Below is my code. In MKDirections its always showing nil. Please let me know what I am doing wrong.
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.activityIndicator.hidden = YES;
self.routeDetailsButton.hidden = YES;
self.routeDetailsButton.enabled = NO;
self.mapView.delegate = self;
self.mapView.showsUserLocation = YES;
self.navigationItem.title = #"RouteMaster";
}
#pragma mark - MapKit delegate methods
- (void)mapView:(MKMapView *)aMapView didUpdateUserLocation:(MKUserLocation *)userLocation {
CLLocationCoordinate2D loc = [userLocation.location coordinate];
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(loc, 1000.0f, 1000.0f);
[self.mapView setRegion:region animated:YES];
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (IBAction)handleRoutePressed:(id)sender {
// We're working
CLLocationCoordinate2D sourceCoords = CLLocationCoordinate2DMake(28.6100, 77.2300);
MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:sourceCoords addressDictionary:nil];
MKMapItem *srcMapItem = [[MKMapItem alloc]initWithPlacemark:sourcePlacemark];
CLLocationCoordinate2D destinationCoords = CLLocationCoordinate2DMake(18.9750, 72.8258);
MKPlacemark *destinationPlacemark = [[MKPlacemark alloc] initWithCoordinate:destinationCoords addressDictionary:nil];
MKMapItem *distMapItem = [[MKMapItem alloc]initWithPlacemark:destinationPlacemark];
MKDirectionsRequest *request = [[MKDirectionsRequest alloc]init];
[request setSource:srcMapItem];
[request setDestination:distMapItem];
MKDirections *direction = [[MKDirections alloc]initWithRequest:request];
[direction calculateDirectionsWithCompletionHandler:^(MKDirectionsResponse *response, NSError *error) {
if (error)
NSLog(#"Error %#", error.description);
else
NSLog(#"response = %#",response);
NSArray *arrRoutes = [response routes];
[arrRoutes enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
MKRoute *rout = obj;
MKPolyline *line = [rout polyline];
[self.mapView addOverlay:line];
NSLog(#"Rout Name : %#",rout.name);
NSLog(#"Total Distance (in Meters) :%f",rout.distance);
NSArray *steps = [rout steps];
NSLog(#"Total Steps : %lu",(unsigned long)[steps count]);
[steps enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSLog(#"Rout Instruction : %#",[obj instructions]);
NSLog(#"Rout Distance : %f",[obj distance]);
}];
}];
}];
}
#pragma mark - Utility Methods
- (void)plotRouteOnMap:(MKRoute *)route
{
if(_routeOverlay) {
[self.mapView removeOverlay:_routeOverlay];
}
// Update the ivar
_routeOverlay = route.polyline;
// Add it to the map
[self.mapView addOverlay:_routeOverlay];
}
#pragma mark - MKMapViewDelegate methods
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay
{
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
renderer.strokeColor = [UIColor redColor];
renderer.lineWidth = 4.0;
return renderer;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay {
if ([overlay isKindOfClass:[MKPolyline class]]) {
MKPolylineView* aView = [[MKPolylineView alloc]initWithPolyline:(MKPolyline*)overlay] ;
aView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.5];
aView.lineWidth = 10;
return aView;
}
return nil;
}
Mostly this error occur if [_mapView setRegion:region] area and polyline route path are not on same region(both should need to display on same screen).
In my case I was searching for USA route path while my region was India. So it wont call to -(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay; function.
add this method
-(MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay {
MKPolylineRenderer * routeLineRenderer = [[MKPolylineRenderer alloc] initWithPolyline:overlay];
routeLineRenderer.strokeColor = [UIColor blueColor];
routeLineRenderer.lineWidth = 4;
return routeLineRenderer;
}
I want to pass information about the location of the user to another function which uses it. The delegate class MyLocation is a singleton which stores this information.
But in my code the didUpdateToLocation never gets called . Should n't it be called at least once whenever startUpdatingLocation is called even if the device is stationary?
I did check if locationmanager.location.coordinate.latitude and locationmanager.location.coordinate.longitude have the right values and they do. The location services are enabled and the user permission to access location services is also granted. I am still building for iOS 5. None of the previously given solutions seem to work for me!
Can someone please give me some idea as to why it is not working?
The code is as follows:
CLLocationManager *locationManager;
CLGeocoder *geocoder;
CLPlacemark *placemark;
#implementation MyLocation {
}
+ (id)getInstance {
static MyLocation *sharedMyLocation = nil;
static int i=0;
if(i==0){
sharedMyLocation = [[MyLocation alloc] init];
i=1;
}
return sharedMyLocation;
}
- (id)init {
if (self = [super init]) {
latitude = [[NSString alloc] init];
longitude = [[NSString alloc] init];
country = [[NSString alloc] init];
admin_area = [[NSString alloc] init];
postal_code = [[NSString alloc] init];
locality = [[NSString alloc] init];
subtfare = [[NSString alloc] init];
tfare = [[NSString alloc] init];
}
return self;
}
- (void) startupdate{
if(locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
if(geocoder == nil)
geocoder = [[CLGeocoder alloc] init];
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if(currentLocation != nil){
longitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
latitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
[locationManager stopUpdatingLocation];
// Reverse Geocoding
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error) {
NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
country = [NSString stringWithFormat:#"%#",placemark.country];
admin_area = [NSString stringWithFormat:#"%#",placemark.administrativeArea];
postal_code = [NSString stringWithFormat:#"%#",placemark.postalCode];
locality = [NSString stringWithFormat:#"%#",placemark.locality];
subtfare = [NSString stringWithFormat:#"%#",placemark.subThoroughfare];
tfare = [NSString stringWithFormat:#"%#",placemark.thoroughfare];
} else {
NSLog(#"%#", error.debugDescription);
}
} ];
}
- (NSString*) getLatitude
{
return latitude;
}
- (NSString*) getLongitude
{
return longitude;
}
- (NSString*) getCountry
{
return country;
}
- (NSString*) getAdminArea
{
return admin_area;
}
- (NSString*) getPostalCode
{
return postal_code;
}
- (NSString*) getLocality
{
return locality;
}
- (NSString*) getSubTFare
{
return subtfare;
}
- (NSString*) getTFare
{
return tfare;
}
error GPS_INTERFACE::getLatitude(char* buffer , unsigned int len)
{
id temp = [MyLocation getInstance];
[temp startupdate];
NSString* tempbuf = [temp getLatitude];
NSString *l = [NSString stringWithFormat:#"%#",tempbuf];
const char* lati= [l UTF8String];
if(strlen(lati) < len)
std::strncpy(buffer,lati,[l length]);
else
return Buffer_Insufficent;
return No_Error;
}
/* other similar getter functions! */
Hi I'm doing an app that must to show a map with the route. I parsed a Json to obtain the points to draw the polyline. I found a a code in the web to draw this polyline. The code I found it's on this link: http://iosguy.com/2012/05/22/tracing-routes-with-mapkit/
Where it says "Create the MKPolyline annotation" I tried to import this in my app, but I'm having problems to create the array of the coordinates. My method is this:
- (void)createMKpolylineAnnotation {
NSInteger numberOfSteps = self.path.count;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * numberOfSteps);
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [self.path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coords[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coords count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
When I try to look the value of coords is setted only the first time, why's that?
Can you help me to solve this problem or i should make in another mode?
I post here the code of the view controller that handle the map view.
MapViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface MapViewController : UIViewController <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic, strong) NSString *fromCity;
#property (nonatomic, strong) NSString *toCity;
- (IBAction)chooseKindOfMap:(id)sender;
#end
MapViewController.m
#import "MapViewController.h"
#import "AppDelegate.h"
#import "PlaceAnnotation.h"
#interface MapViewController ()
#property (nonatomic, strong)NSMutableArray *mapAnnotation;
#property (nonatomic) BOOL needUpdateRegion;
#property (nonatomic, strong)NSMutableArray *path;
#end
#implementation MapViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self parseGoogleJsonToObtainPointsForPolyline];
[self.mapView setDelegate:self];
self.needUpdateRegion = YES;
//[self centerMap];
self.mapAnnotation = [[NSMutableArray alloc]initWithCapacity:2];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
NSLog(#"%d", appDelegate.dataForMap.count);
NSArray* coords = [self getCoords:appDelegate.dataForMap];
NSLog(#"coords = %#", coords);
PlaceAnnotation *fromPlace = [[PlaceAnnotation alloc] initWithCoordinateAndName:coords[0] andLong:coords[1] andName:self.fromCity];
PlaceAnnotation *toPlace = [[PlaceAnnotation alloc] initWithCoordinateAndName:coords[2] andLong:coords[3] andName:self.toCity];
[self.mapAnnotation insertObject:fromPlace atIndex:0];
[self.mapAnnotation insertObject:toPlace atIndex:1];
NSLog(#"mapAnnotation.count: %d", self.mapAnnotation.count);
if (self.mapAnnotation) {
[self.mapView removeAnnotations:self.mapView.annotations];
}
[self.mapView addAnnotation:self.mapAnnotation[0]];
[self.mapView addAnnotation:self.mapAnnotation[1]];
NSLog(#"MapAnnotation = %#", self.mapView.annotations);
[self updateRegion];
[self createMKpolylineAnnotation];
}
//- (void)viewDidAppear:(BOOL)animated {
// [super viewDidAppear:animated];
// if (self.needUpdateRegion) [self updateRegion];
//}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (MKAnnotationView*)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
MKPinAnnotationView *pin = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:nil];
pin.pinColor = MKPinAnnotationColorRed;
return pin;
}
- (void)mapView:(MKMapView *)mapView didAddAnnotationViews:(NSArray *)views {
MKPinAnnotationView *ulv = [mapView viewForAnnotation:mapView.userLocation];
ulv.hidden = YES;
}
- (NSArray*)getCoords:(NSDictionary*)data {
NSArray *legs = [data objectForKey:#"legs"];
NSDictionary *firstZero = [legs objectAtIndex:0];
NSDictionary *endLocation = [firstZero objectForKey:#"end_location"];
NSDictionary *startLocation = [firstZero objectForKey:#"start_location"];
NSString *latFrom = [startLocation objectForKey:#"lat"];
NSString *lngFrom = [startLocation objectForKey:#"lng"];
NSString *latTo = [endLocation objectForKey:#"lat"];
NSString *lngTo = [endLocation objectForKey:#"lng"];
return #[latFrom,lngFrom,latTo,lngTo];
}
- (void)centerMap {
MKCoordinateRegion region;
region.center.latitude = 41.178654;
region.center.longitude = 11.843262;
region.span.latitudeDelta = 11.070406;
region.span.longitudeDelta = 12.744629;
[self.mapView setRegion:region];
}
- (IBAction)chooseKindOfMap:(id)sender {
if ([sender tag] == 0) {
self.mapView.mapType = MKMapTypeStandard;
}
if ([sender tag] == 1) {
self.mapView.mapType = MKMapTypeSatellite;
}
if ([sender tag] == 2) {
self.mapView.mapType = MKMapTypeHybrid;
}
}
- (void)updateRegion
{
self.needUpdateRegion = NO;
CGRect boundingRect;
BOOL started = NO;
for (id <MKAnnotation> annotation in self.mapView.annotations) {
CGRect annotationRect = CGRectMake(annotation.coordinate.latitude, annotation.coordinate.longitude, 0, 0);
if (!started) {
started = YES;
boundingRect = annotationRect;
} else {
boundingRect = CGRectUnion(boundingRect, annotationRect);
}
}
if (started) {
boundingRect = CGRectInset(boundingRect, -0.2, -0.2);
if ((boundingRect.size.width < 20) && (boundingRect.size.height < 20)) {
MKCoordinateRegion region;
region.center.latitude = boundingRect.origin.x + boundingRect.size.width / 2;
region.center.longitude = boundingRect.origin.y + boundingRect.size.height / 2;
region.span.latitudeDelta = boundingRect.size.width;
region.span.longitudeDelta = boundingRect.size.height;
[self.mapView setRegion:region animated:YES];
}
}
}
- (void)parseGoogleJsonToObtainPointsForPolyline {
NSDictionary *polyline;
NSMutableArray *points = [[NSMutableArray alloc]init];;
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
NSArray *legs = [appDelegate.dataForMap objectForKey:#"legs"];
NSDictionary *firstZero =[legs objectAtIndex:0];
NSArray *steps = [firstZero objectForKey:#"steps"];
for (int i = 0; i < steps.count; i++) {
polyline = [steps[i] objectForKey:#"polyline"];
[points addObject:polyline[#"points"]];
NSLog(#"POINTS = %#", polyline[#"points"]);
self.path = [self decodePolyLine:points[i]];
}
NSLog(#"path = %#", self.path);
}
-(NSMutableArray *)decodePolyLine:(NSString *)encodedStr {
NSMutableString *encoded = [[NSMutableString alloc] initWithCapacity:[encodedStr length]];
[encoded appendString:encodedStr];
[encoded replaceOccurrencesOfString:#"\\\\" withString:#"\\"
options:NSLiteralSearch
range:NSMakeRange(0, [encoded length])];
NSInteger len = [encoded length];
NSInteger index = 0;
NSMutableArray *array = [[NSMutableArray alloc] init];
NSInteger lat=0;
NSInteger lng=0;
while (index < len) {
NSInteger b;
NSInteger shift = 0;
NSInteger result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlat = ((result & 1) ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = [encoded characterAtIndex:index++] - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
NSInteger dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
lng += dlng;
NSNumber *latitude = [[NSNumber alloc] initWithFloat:lat * 1e-5];
NSNumber *longitude = [[NSNumber alloc] initWithFloat:lng * 1e-5];
CLLocation *location = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]];
[array addObject:location];
}
return array;
}
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay {
MKPolylineView *polylineView = [[MKPolylineView alloc] initWithPolyline:overlay];
polylineView.strokeColor = [UIColor redColor];
polylineView.lineWidth = 1.0;
return polylineView;
}
- (void)createMKpolylineAnnotation {
NSInteger numberOfSteps = self.path.count;
CLLocationCoordinate2D *coords = malloc(sizeof(CLLocationCoordinate2D) * numberOfSteps);
for (NSInteger index = 0; index < numberOfSteps; index++) {
CLLocation *location = [self.path objectAtIndex:index];
CLLocationCoordinate2D coordinate = location.coordinate;
coords[index] = coordinate;
}
MKPolyline *polyLine = [MKPolyline polylineWithCoordinates:coords count:numberOfSteps];
[self.mapView addOverlay:polyLine];
}
#end
I used the AppDelegate to have the Json (I parsed it in another class)
Here is a tutorial how to add a polyline to a mapView. Hope this helps!
EDIT:
Unfortunately, the link provided above is now broken, and I am not able to find the tutorial referred to.
simple, just copy and paste my code and modify some variables
- (IBAction)traceRoute:(UIButton *)sender {
double latDouble = 39.7540615;
double lngDouble = -8.8059587;
// double latDouble = [self.sheetDetail.data.locationLat doubleValue];
// double lngDouble = [self.sheetDetail.data.locationLng doubleValue];
CLLocationCoordinate2D c2D = CLLocationCoordinate2DMake(latDouble, lngDouble);
MKPlacemark *placemark = [[MKPlacemark alloc] initWithCoordinate:c2D addressDictionary:nil];
MKMapItem *mapItem = [[MKMapItem alloc] initWithPlacemark:placemark];
[mapItem setName:#"Mobile Edge"];
MKPlacemark *placemark2;
MKMapItem *mapItem2;
if(kIS_OS_8_OR_LATER) {
placemark2 = [[MKPlacemark alloc] initWithCoordinate:_userLoc addressDictionary:nil];
mapItem2 = [[MKMapItem alloc] initWithPlacemark:placemark2];
[mapItem2 setName:#"Me"];
} else {
placemark2 = [[MKPlacemark alloc] initWithCoordinate:_mapView.userLocation.coordinate addressDictionary:nil];
mapItem2 = [[MKMapItem alloc] initWithPlacemark:placemark2];
[mapItem2 setName:#"Me"];
}
MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init];
request.source = mapItem2;
request.destination = mapItem;
request.requestsAlternateRoutes = NO;
MKDirections *directions = [[MKDirections alloc] initWithRequest:request];
[directions calculateDirectionsWithCompletionHandler:
^(MKDirectionsResponse *response, NSError *error) {
if (error) {
// Handle error
[[NSNotificationCenter defaultCenter] postNotificationName:#"finishedLocationRoute" object:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: NSLocalizedString(#"Route error title", nil)
message: NSLocalizedString(#"Route error", nil)
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
} else {
for (MKRoute *route in response.routes)
{
//MKMapPoint middlePoint = route.polyline.points[route.polyline.pointCount/2];
//[self createAndAddAnnotationForCoordinate:MKCoordinateForMapPoint(middlePoint) andRoute:route];
[self.mapView addOverlay:route.polyline level:MKOverlayLevelAboveRoads];
}
//notifies parent menu
//[[NSNotificationCenter defaultCenter] postNotificationName:#"finishedLocationRoute" object:nil];
}
}];
}
- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id)overlay
{
if (![overlay isKindOfClass:[MKPolygon class]]) {
MKPolyline *route = overlay;
MKPolylineRenderer *renderer = [[MKPolylineRenderer alloc] initWithPolyline:route];
renderer.strokeColor = [UIColor blueColor];
renderer.lineWidth = 5.0;
return renderer;
} else {
return nil;
}
}