So I'm attempting to integrate the user's current location with my iOS project - I'm using some third part code to build out the map with the pinpoints - I have these frameworks integrated:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <QuartzCore/QuartzCore.h>
#import <MapKit/MapKit.h>
here's my code with the pinpoints - any help would be greatly appreciated:
#import "asyMap.h"
#implementation asyMap
#synthesize currentAnnotation,mapAnnotations,map,prompt,mapFromLink,selectedAnnotationId,selectedAnnotationIndex,showOthers,useCustomTitle,customTitle;
/**
* Class constructor
*/
-(id)init{
self = [super init];
if(self){
useCustomTitle = FALSE;
mapFromLink = FALSE;
showOthers = FALSE;
map = [[asyMapObject alloc] init];
[map addOnView:self.view];
}
return self;
}
/**
* Overwrite the set page method in
* order to show a selected annotation
* from a link
*/
-(void)setPage:(NSDictionary *)page{
NSDictionary *metas = [page valueForKey:#"metas"];
if([metas valueForKey:#"selectedAnnotationPageTitle"] && ![[[metas valueForKey:#"selectedAnnotationPageTitle"] stringValue] isEqualToString:#""] && customTitle == nil){
useCustomTitle = TRUE;
NSString *newTitle = [metas valueForKey:#"selectedAnnotationPageTitle"];
customTitle = [[NSString alloc] initWithString:[[newTitle stringByReplacingOccurrencesOfString:#"+" withString:#" "] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
}
if(useCustomTitle && customTitle != nil){
NSMutableDictionary *pageWithCustomTitle = [[NSMutableDictionary alloc] initWithDictionary:page];
[pageWithCustomTitle setValue:customTitle forKey:#"title"];
[super
setPage:pageWithCustomTitle];
}else{
[super setPage:page];
}
if([metas valueForKey:#"annotationFromLink"] && [[[metas valueForKey:#"annotationFromLink"] stringValue] isEqualToString:#"yes"] && selectedAnnotationId == nil){
selectedAnnotationId = [[NSString alloc] initWithString:[metas valueForKey:#"selectedAnnotation"]];
mapFromLink = TRUE;
showOthers = [[[metas valueForKey:#"showOthers"] stringValue] isEqualToString:#"yes"];
}else if(mapFromLink && selectedAnnotationId != nil){
mapFromLink = FALSE;
NSArray *annotations = [page valueForKey:#"annotations"];
for(int a = 0; a < [annotations count]; a++){
NSDictionary *annotation = [annotations objectAtIndex:a];
if([[[annotation valueForKey:#"annotationId"] stringValue] isEqualToString:selectedAnnotationId]){
mapFromLink = TRUE;
selectedAnnotationIndex = a;
break;
}
}
}
}
/**
* Set the module's name
*/
-(void)makeProcess{
[self setModuleName:#"map"];
}
/**
* Create the basic prompt alert
*/
-(void)buildModule{
prompt = [[UIAlertView alloc] initWithTitle:#"" message:[theme asy__:#"Open on the Maps app?"] delegate:self cancelButtonTitle:[theme asy__:#"No"] otherButtonTitles:[theme asy__:#"Yes"], nil];
}
/**
* Set the annotations after get the page data
*/
-(void)requestedPage:(NSDictionary *)pageInformation{
[self setPage:pageInformation];
if(mapFromLink && !showOthers && [[self getPageMapAnnotations] count] > 0){
NSArray *pageAnnotations = [self getPageMapAnnotations];
mapAnnotations = [[NSArray alloc] initWithObjects:[pageAnnotations objectAtIndex:selectedAnnotationIndex],nil];
}else{
mapAnnotations = [[NSArray alloc] initWithArray:[self getPageMapAnnotations]];
}
[map setMapAnnotations:mapAnnotations andDelegate:self];
if(mapFromLink){
[map focusMapOnAnnotationAtIndex:(showOthers ? selectedAnnotationIndex : 0)];
}
[map build];
[self hideLoading];
[self checkPageOptionButton];
}
/**
* The module orientation did change
*/
-(void)moduleOrientationDidChange{
[map setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
}
#pragma mark - Map Delegate
/**
* Check if the annotation has properties for action or the prompt to be opened
* on the Maps app should appear
*/
-(void)asyMapObject:(asyMapObject *)mapObject didSelectAnnotation:(NSDictionary *)annotation atIndex:(NSInteger)index{
currentAnnotation = index;
if([[annotation valueForKey:#"menuId"] isEqualToString:#"0"] &&
[[annotation valueForKey:#"pageId"] isEqualToString:#"0"] &&
[[annotation valueForKey:#"link"] isEqualToString:#""] &&
[[annotation valueForKey:#"url"] isEqualToString:#""] &&
[[annotation valueForKey:#"phpfile"] isEqualToString:#""]){
[prompt setTitle:[annotation valueForKey:#"title"]];
[prompt show];
}else{
AppsifymeCore *core = [AppsifymeCore sharedAppsifymeCore];
[core basicHandlerForMultiActionsOption:annotation];
}
}
#pragma mark - Alert view delegate
/**
* Detect if the user wants to open the annotation on the maps app, and if its
* true, this method build the link and open the app
*/
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if(buttonIndex != 1) return;
AppsifymeCore *core = [AppsifymeCore sharedAppsifymeCore];
NSDictionary *annotation = [mapAnnotations objectAtIndex:currentAnnotation];
float latitude = [[annotation valueForKey:#"latitude"] floatValue];
float longitude = [[annotation valueForKey:#"longitude"] floatValue];
if(![core asyiOS6]){
NSString *pinName = [[NSString alloc] initWithString:[core encodeURLParameter:[annotation valueForKey:#"title"]]];
int zoom = 13;
NSString *stringURL = [[NSString alloc] initWithFormat:#"http://maps.apple.com/maps?q=%##%1.6f,%1.6f&z=%d", pinName, latitude, longitude, zoom];
NSURL *url = [[NSURL alloc] initWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
}else{
Class itemClass = [MKMapItem class];
if (itemClass && [itemClass respondsToSelector:#selector(openMapsWithItems:launchOptions:)]) {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(latitude,longitude);
MKPlacemark *placeMark = [[MKPlacemark alloc] initWithCoordinate:coordinate addressDictionary:nil];
MKMapItem *item = [[MKMapItem alloc] initWithPlacemark:placeMark];
item.name = [[annotation valueForKey:#"title"] stringValue];
[item openInMapsWithLaunchOptions:nil];
}
}
}
#end
In your init method, add this line
self.showsUserLocation = YES;
Related
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.
I am trying to add multiple waypoints to my google directions request.
When I add a single waypoint like
https://maps.googleapis.com/maps/api/directions/json?&origin=51.507679,-0.125004&waypoints=51.524151,-0.123174&destination=51.495777,-0.108642&mode=walking
it works fine but when I try to add multiple waypoints like
https://maps.googleapis.com/maps/api/directions/json?&origin=51.606502,0.527309&waypoints=51.507679,-0.125004|51.524151,-0.123174&destination=51.495777,-0.108642&mode=walking
i receive a 'unsupported URL' error. What is the correct way to add multiple waypoints? Thanks
Its very simple, Just replace '|' with '%%7C'
Your updated url will be :
https://maps.googleapis.com/maps/api/directions/json?&origin=51.606502,0.527309&waypoints=51.507679,-0.125004%%7C51.524151,-0.123174&destination=51.495777,-0.108642&mode=walking
Happy Coding
I give you the solution step by step
First we should get the Google Map SDK
Drag the following bundles into your project (when prompted, select Copy items if needed):
Subspecs/Base/Frameworks/GoogleMapsBase.framework
Subspecs/Maps/Frameworks/GoogleMaps.framework
Subspecs/Maps/Frameworks/GoogleMapsCore.framework
Right-click GoogleMaps.framework in your project, and select Show In Finder.
Drag the GoogleMaps.bundle from the Resources folder into your project. When prompted, ensure Copy items into destination group's folder is not selected.
Select your project from the Project Navigator, and choose your application's target.
Open the Build Phases tab, and within Link Binary with Libraries, add the following frameworks:
GoogleMapsBase.framework
GoogleMaps.framework
GoogleMapsCore.framework
GoogleMapsM4B.framework (Premium Plan customers only)
Accelerate.framework
CoreData.framework
CoreGraphics.framework
CoreLocation.framework
CoreText.framework
GLKit.framework
ImageIO.framework
libc++.tbd
libz.tbd
OpenGLES.framework
QuartzCore.framework
SystemConfiguration.framework
UIKit.framework
Now Get the API key
Now you need to add following things in Plist
AppDelegate.m
#import GoogleMaps;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[GMSServices provideAPIKey:#"YOUR API KEY"];
return YES;
}
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <GoogleMaps/GoogleMaps.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate,GMSMapViewDelegate>{
CLLocation *currentLocation;
}
#property (strong, nonatomic) IBOutlet UIView *viewMarker;
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) GMSMapView *mapView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize viewMarker,locationManager,
#synthesize mapView;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
locationManager = [[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager.distanceFilter = 10;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if([CLLocationManager locationServicesEnabled] == NO){
NSLog(#"Your location service is not enabled, So go to Settings > Location Services");
}
else{
NSLog(#"Your location service is enabled");
}
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate method
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
currentLocation = [locations lastObject];
if (currentLocation != nil){
NSLog(#"The latitude value is - %#",[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude]);
NSLog(#"The logitude value is - %#",[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude]);
}
//Current
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:currentLocation.coordinate.latitude longitude: currentLocation.coordinate.longitude zoom:13];
self.mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
self.mapView.myLocationEnabled = YES;
self.mapView.delegate = self;
self.mapView.frame = viewMarker.bounds;
[viewMarker addSubview:self.mapView];
GMSMarker *marker1 = [[GMSMarker alloc] init];
//Current
marker1.position = CLLocationCoordinate2DMake(currentLocation.coordinate.latitude, currentLocation.coordinate.longitude);
marker1.icon = [UIImage imageNamed:#"boss-icon.png"];
marker1.map = self.spyMapView;
NSArray *arrLatLongValue = #[
#{
#"Latitude":#"12.9003",
#"Longitude":#"80.2278"
},
#{
#"Latitude":#"12.8447",
#"Longitude":#"80.2254"
},
#{
#"Latitude":#"12.7726",
#"Longitude":#"80.2488"
},
#{
#"Latitude":#"12.9171",
#"Longitude":#"80.1923"
}
];
NSString *strWayPoints = [NSString stringWithFormat:#"via:%f,%f", [arrLatLongValue[0][#"Latitude"] doubleValue], [arrLatLongValue[0][#"Longitude"] doubleValue]];
for(int j=0;j<arrLatLongValue.count;j++){
CLLocationCoordinate2D position = { [[arrLatLongValue[j] objectForKey:#"Latitude"] doubleValue], [[arrLatLongValue[j] objectForKey:#"Longitude"] doubleValue] };
GMSMarker *marker = [GMSMarker markerWithPosition:position];
marker.title = [NSString stringWithFormat:#"Marker %i", j];
marker.appearAnimation = YES;
marker.flat = YES;
if(j < 2)
marker.icon = [GMSMarker markerImageWithColor:[UIColor redColor]];
else if(j >= 2 && j < 4)
marker.icon = [GMSMarker markerImageWithColor:[UIColor purpleColor]];
else
marker.icon = [GMSMarker markerImageWithColor:[UIColor greenColor]];
if(j > 0)
strWayPoints = [NSString stringWithFormat:#"%#|via:%f,%f", strWayPoints, [arrLatLongValue[j][#"Latitude"] doubleValue], [arrLatLongValue[j][#"Longitude"] doubleValue]];
marker.map = self.mapView;
}
//Current
NSString *originString = [NSString stringWithFormat:#"%f,%f",currentLocation.coordinate.latitude, currentLocation.coordinate.longitude];
NSString *destinationString = [NSString stringWithFormat:#"%f,%f", #(12.9220085).doubleValue, #(80.0954032).doubleValue];
NSString *str = [NSString stringWithFormat:#"https://maps.googleapis.com/maps/api/directions/json?origin=%#&destination=%#&waypoints=%#&key=YOUR API KEY",originString,destinationString,strWayPoints];
NSURL *url=[[NSURL alloc]initWithString:[str stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]]];
NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
NSURLSessionDataTask * dataTask = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if(data == nil) {
return;
}else{
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
NSArray* latestRoutes = [json objectForKey:#"routes"];
NSString *points=[[[latestRoutes objectAtIndex:0] objectForKey:#"overview_polyline"] objectForKey:#"points"];
#try {
// TODO: better parsing. Regular expression?
NSArray *temp= [self decodePolyLine:[points mutableCopy]];
GMSMutablePath *path = [GMSMutablePath path];
for(int idx = 0; idx < [temp count]; idx++){
CLLocation *location=[temp objectAtIndex:idx];
[path addCoordinate:location.coordinate];
}
// create the polyline based on the array of points.
GMSPolyline *rectangle = [GMSPolyline polylineWithPath:path];
rectangle.strokeWidth=5.0;
rectangle.map = self.spyMapView;
[locationManager stopUpdatingLocation];
}
#catch (NSException * e) {
// TODO: show erro
}
}
}];
[dataTask resume];
}
[locationManager stopUpdatingLocation];
}
pragma mark - Drawing Lines
-(NSMutableArray *)decodePolyLine: (NSMutableString *)encoded {
[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] ;
printf("[%f,", [latitude doubleValue]);
printf("%f]", [longitude doubleValue]);
CLLocation *loc = [[CLLocation alloc] initWithLatitude:[latitude floatValue] longitude:[longitude floatValue]] ;
[array addObject:loc];
}
return array;
}
I am inserting some annotations that are coming from a json server, but I wanted to check if the annotation is already on the map, if so, does not add it again. For they are being added on each other , have someone help me solve this problem?
my code:
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
[annotationsPins addObject:myAnn];
}
[self.mapView addAnnotations:annotationsPins];
}
You can iterate through annotations already on MkMapView and see if they are already there:
NSArray * annotations = [self.mapView.annotations copy];
for (NSDictionary *annotationDeProdutos in objetos)
{
// Check if annotation in annotations are duplicate of annotationDeProdutos.
// You can match using name.
}
Or the other way if you only want to show annotations from single server call:
[self.mapView removeAnnotations: self.mapView.annotations];
// Now add from JSON response.
You can do this for each of your annotations:
if(![self.mapView.annotations containsObject: myAnn]) {
[self.mapView addAnnotations: myAnn];
}
I solved the problem with this code :
// adiciona produtos ao mapa
- (void)adicionaAnnotationsNoMapa:(id)objetos{
NSMutableArray *annotationsPins = [[NSMutableArray alloc] init];
for (NSDictionary *annotationDeProdutos in objetos) {
CLLocationCoordinate2D location;
AnnotationMap *myAnn;
myAnn = [[AnnotationMap alloc] init];
location.latitude = [[annotationDeProdutos objectForKey:#"latitude"] floatValue];
location.longitude = [[annotationDeProdutos objectForKey:#"longitude"] floatValue];
myAnn.coordinate = location;
myAnn.title = [annotationDeProdutos objectForKey:#"name"];
myAnn.subtitle = [NSString stringWithFormat:#"R$ %#",[annotationDeProdutos objectForKey:#"price"]];
myAnn.categoria = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id_categoria"]];
myAnn.idProduto = [NSString stringWithFormat:#"%#", [annotationDeProdutos objectForKey:#"id"]];
if (self.mapView.annotations.count <1) {
[annotationsPins addObject:myAnn];
} else {
__block NSInteger foundIndex = NSNotFound;
[annotationsPins enumerateObjectsUsingBlock:^(AnnotationMap *annotation, NSUInteger idx, BOOL *stop) {
CLLocation *loc1 = [[CLLocation alloc] initWithLatitude:location.latitude longitude:location.longitude];
CLLocation *loc2 = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
if ([loc1 distanceFromLocation:loc2] <= 1.0f) {
foundIndex = idx;
*stop = YES;
}
}];
if (foundIndex != NSNotFound) {
[annotationsPins addObject:myAnn];
}
}
}
[self.mapView addAnnotations:annotationsPins];
}
First of all I am running a Map page that just only show pins on map for every store. I was running only one pin on the map and it was fast after I put more than 25 pins it push very slow to the map page. What it is doing now at that process the app just load all data of the pin location (as I see in the target output) and then it push to the next screen. So please where would be my problem?
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = #"";
self.navigationItem.title = #"Mek";
response = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:#"http://kalkatawi.com/mapLocation.php"]];
if(response!=nil) {
NSError *parseError = nil;
jsonArray = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingAllowFragments error:&parseError];
jsonArray1 = [[NSMutableArray alloc] init];
jsonArray2 = [[NSMutableArray alloc] init];
jsonArray3 = [[NSMutableArray alloc] init];
for(int i=0;i<[jsonArray count];i++)
{
name = [[jsonArray objectAtIndex:i] objectForKey:#"name"];
longitude = [[jsonArray objectAtIndex:i] objectForKey:#"longitude"];
latitude = [[jsonArray objectAtIndex:i] objectForKey:#"latitude"];
[jsonArray1 addObject:name];
[jsonArray2 addObject:longitude];
[jsonArray3 addObject:latitude];
self.locationMap.delegate = self; //set delegate before adding annotations
CLLocationCoordinate2D annotationCoord;
for (int i=0; i < [jsonArray count]; i++)
{
NSDictionary *annotationDictionary = [jsonArray objectAtIndex:i];
name = [annotationDictionary objectForKey:#"name"];
annotationCoord.latitude
= [[annotationDictionary objectForKey:#"longitude"] doubleValue];
annotationCoord.longitude
= [[annotationDictionary objectForKey:#"latitude"] doubleValue];
MKPointAnnotation *annotationPoint = [[MKPointAnnotation alloc] init];
annotationPoint.coordinate = annotationCoord;
annotationPoint.title = name;
annotationPoint.subtitle = [NSString stringWithFormat:#"%f %f", annotationPoint.coordinate.latitude, annotationPoint.coordinate.longitude];
[self.locationMap addAnnotation:annotationPoint];
//------------------------//
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(annotationPoint.coordinate, 50000, 50000);
[self.locationMap setRegion:[self.locationMap regionThatFits:region] animated:YES];
locationManager = [[CLLocationManager alloc] init];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
lat = locationManager.location.coordinate.latitude;
lon = locationManager.location.coordinate.longitude;
}
}
}
else {
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"You are not connected to internet" message:#"Please check the internet connection" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
- (MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id <MKAnnotation>)annotation
{
MKAnnotationView *pinView = nil;
if(annotation != locationMap.userLocation)
{
static NSString *defaultPinID = #"myPin";
pinView = (MKAnnotationView *)[locationMap dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
if ( pinView == nil )
pinView = [[[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID] autorelease];
pinView.image = [UIImage imageNamed:#"pinpinpin.png"];
pinView.canShowCallout = YES;
pinView.enabled = YES;
UIButton *infoButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
pinView.rightCalloutAccessoryView = infoButton;
}
return pinView;
}
SImple way is load data in background thread, and then when data is fully load display it on the map. You can do this in any of view controller, means you can do it in parent view controller and when you got response then update on map view controller.
Or on view did load method load data in background and update it when its load. This approach will not hold your UI. You can use blocks like this
dispatch_async(queue, ^{
//load data from server
dispatch_async(dispatch_get_main_queue(), ^{
//Update map
});
});
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;
}
}