i am using here maps in my app and works fine. i pass destination coordinate from one view controller to another viewcontroller which contains here map and its methods. i tried to get the current location inside the method in the second view controller to calculate the roue, but current location always returns 0,0.please advice how to get current location inside the method where i pass the values from first viewcontroller
viewcontroller1:
- (IBAction)btn_navigate:(id)sender
{
NSLog(#"%#",_POiarray);
_VC=[[NaviMeVC alloc]init];
[_VC GetPoi:_POiarray];
[self.navigationController pushViewController:_VC animated:YES];
}
mapviewcontroller:
-(void)GetPoi:(NSMutableArray *)anArray
{
//get current location
NMAGeoPosition * position=[[NMAGeoPosition alloc]init];
position = [[NMAPositioningManager sharedPositioningManager] currentPosition];
_StartCoordinate=[[NMAGeoCoordinates alloc]initWithLatitude:position.coordinates.latitude longitude:position.coordinates.longitude];
//not working returns nil
[[NMAMapLoader sharedMapLoader] setDelegate:self];
_SelectedPOi=[[NSMutableArray alloc]init];
_SelectedPOi=anArray;
NSString *lat=[anArray valueForKey:#"latitude"];
CLLocationDegrees latitu=[lat doubleValue];
NSString *longi=[anArray valueForKey:#"longitude"];
CLLocationDegrees longit=[longi doubleValue];
_DestinationCoordinate=[[NMAGeoCoordinates alloc]initWithLatitude:latitu longitude:longit];
NSLog(#"%f %f",_DestinationCoordinate.latitude,_DestinationCoordinate.longitude);
NSNumber *lati = [NSNumber numberWithDouble:latitu];
NSNumber *longitu = [NSNumber numberWithDouble:longit];
NSDictionary *userLocation=#{#"lat":lati,#"long":longitu};
NMARoutingMode* routingMode = [[NMARoutingMode alloc] initWithRoutingType:NMARoutingTypeShortest
transportMode:NMATransportModeCar
routingOptions:0];
[self CalculateRoute:routingMode];
}
To start receiving positioning updates you need to call NMAPositioningManager startPositioning which I don't see in your sample code. More details in user guide link below. Please read the other instructions on that page to see if anything helps.
Another thing to check: have you added NSLocationWhenInUseUsageDescription into your projects Info.plist file to ensure your app can receive user location from CLLocationManager?
Also, this may seem obvious but please keep in mind that you will only be able to receive a valid value for currentPosition if you have a position fix.
Positioning User Guide
NMAPositioningManager Doxygen
Related
I have an iPad app that has a feature that shows a region in a MKMapView along with the user's location. This used to work fine, but now it always displays the entire U.S. as the region no matter what I set it as. It does however correctly show the user's location.
The code that sets the region is...
MKCoordinateSpan span = {.latitudeDelta = latSpan, .longitudeDelta = longSpan};
MKCoordinateRegion mapRegion = {center, span};
[self.mapView setRegion:mapRegion];
The values for these variables are...
center = {latitude = 37.525553000000002, longitude = -121.9351005}
latSpan = 0.0029800000000008708
longSpan = 0.011071000000001163
I've double checked, and the center is exactly the location I want, but it doesn't matter what values I put for any of these, I always just get the entire U.S. as the region.
Any ideas what has changed or what I overlooked?
I would really appreciate any help as this driving me crazy...
MapKit will be unable to zoom into the user's location if authorization is not provided by the user.
The result can be that only a display of the United States is shown.
Request permission using:
let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
Also add the key NSLocationWhenInUseUsageDescription to your target's Info.plist. The type is a string and is shown to the user during the authorization request.
Not to put too fine a point on it: you're lying. I ran your code with your values and it works perfectly:
The code for this app consists entirely of your values and your code:
#import "ViewController.h"
#import MapKit;
#interface ViewController ()
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
CLLocationCoordinate2D center = {37.525553000000002, -121.9351005};
double latSpan = 0.0029800000000008708;
double longSpan = 0.011071000000001163;
MKCoordinateSpan span = {.latitudeDelta = latSpan, .longitudeDelta = longSpan};
MKCoordinateRegion mapRegion = {center, span};
[self.mapView setRegion:mapRegion];
}
#end
So clearly you are not telling the truth; you're leaving out something important about what you're doing, because when I do what you say you're doing, I get the right result.
Hey so I have a map view that zooms in on the users location upon view load. Currently I find the users location using the CLLocationManager and initialize the map in the didUpdateLocations delegate method. However, as this is called multiple times I use a global BOOL that is set to true after the map is set once and then never set it again. Here is the code:
Define global BOOL and set it to false in the viewDidLoad:
#implementation MainMapViewController
{
BOOL hasInitializedMap;
}
- (void)viewDidLoad
{
[super viewDidLoad];
hasInitializedMap = NO;
}
I then get the user's location and set the maps zoom inside the (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations delegate method:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
[self initializeMainMapView:location.coordinate.longitude latitude:location.coordinate.latitude];
}
- (void)initializeMainMapView:(float)longitude latitude:(float)latitude
{
if (!hasInitializedMap)
{
CLLocationCoordinate2D zoomLocation;
zoomLocation.latitude = latitude;
zoomLocation.longitude = longitude;
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 1500, 1500);
[mainMapView setRegion:viewRegion animated:YES];
hasInitializedMap = YES;
}
}
This code works but has left me wondering if there is a better way to do this. I hate using global flags like this as it can make your code confusing and is sloppy at best. Is there a better way to do what I am trying to do? Is there a delegate method that only gets called when the users position is updated for the first time? Can I do this with just the MKMapView and forget CoreLocation altogether?
I've done it a few ways... in fact the framework has been changed a few times so I can't remember how I settled on it. The MKMapkit does have a method for showing user location, developer doc:
This property does not indicate whether the user’s position is actually visible on the map, only whether the map view should try to display it. Setting this property to YES causes the map view to use the Core Location framework to find the current location and try to display it on the map. As long as this property is YES, the map view continues to track the user’s location and update it periodically. The default value of this property is NO.
Showing the user’s location does not guarantee that the location is visible on the map. The user might have scrolled the map to a different point, causing the current location to be offscreen. To determine whether the user’s current location is currently displayed on the map, use the userLocationVisible property.
The user's location will appear as an annotation. You can get the annotation and zoom in on that. what would be better would be to use that flag in conjunction with the MKMapViewDelegate which has a method -mapView:DidUpdateUserslocation:
delegate documentation
Maybe after you get the first one you can change the map's tracking mode to none (i'm not sure if that removes the user location annotation or not, if it does, you can easily drop a map pin there with the proper skin). -setUserTrakingMode:animated: is the method on MKMap can use for that.
One thing I would caution on, in writing apps that work with user location in the past, it take a few seconds to get an accurate location. You might want to let the GPS ping a few times first before you lock in on a position. I've found that the first few ticks can be wildly inaccurate. Hope that helps.
I started using Xcode a couple days ago and I'm completely lost. I'm trying to get a GPS locator app running found here.
Basically, the app prints any updated GPS information using NSLog, which as far as my understanding goes, prints to Xcode's console. However, I'd like to get this info printed onto the screen.
Here's the code from CFAStartViewController.m that successfully prints to the screen:
-(void)viewDidAppear:(BOOL)animated{
CFAAppDelegate *appDelegate=(CFAAppDelegate *)[UIApplication sharedApplication].delegate;
CLLocation *currentLocation=appDelegate.locationManager.location;
self.labelLocationInformation.text=[NSString stringWithFormat:#"latitude: %+.6f\nlongitude: %+.6f\naccuracy: %f",
currentLocation.coordinate.latitude,
currentLocation.coordinate.longitude,
currentLocation.horizontalAccuracy];
}
And here's the code in CFAAppDelegate.m that successfully prints to the console:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0)
{
//Location timestamp is within the last 15.0 seconds, let's use it!
if(newLocation.horizontalAccuracy<35.0){
//Location seems pretty accurate, let's use it!
NSLog(#"latitude %+.6f, longitude %+.6f\n",
newLocation.coordinate.latitude,
newLocation.coordinate.longitude);
NSLog(#"Horizontal Accuracy:%f", newLocation.horizontalAccuracy);
//Optional: turn off location services once we've gotten a good location
//[manager stopUpdatingLocation];
}
}
}
I tried changing the calls to NSLog to self.labelLocationInformation.text, with a similar format to that of CFAStartViewController, but it doesn't seem to do anything. I've read through the basic tutorials of Xcode, but I feel there's some knowledge lacking (obviously) on what to do overall.
If the best you could do is post a link that helps me solve this problem, that would be great.
I think the problem is due to scope - the didUpdateToLocation: method is sent to the location manager delegate, ie your app delegate, which doesn't have the label in scope. Try changing your delegate for the location manager to be your CFAStartViewController, and move the associated location manager delegate code from App Delegate to CFAStartViewController. Then the label will be in scope when didUpdateToLocation: is called.
Based on your clarifying response to my comment.... If you want the data from CFAAppDelegate to be presented in your CFAStartViewController then you need to send that data to CFAStartViewController (or CFAStartViewController needs to get it). To send it 1) provide a storyboard id for CFAStartViewController such as "CFAVC". 2) define or expose properties in CFAStartViewController to contain your data. 3) instantiate CFAStartViewController via the following from within CFAAppDelegate:
// in CFAStartViewController.h define property such as:
#property (strong, nonatomic) CLLocation *incomingLocation;
// in CFAAppDelegate.m
// get a pointer to your VC
CFAStartViewController *destinationVC = [self.storyboard instantiateViewControllerWithIdentifier:#"CFAVC"];
// set properties on VC
destinationVC.incomingLocation = newLocation;
// show CFAStartViewController (or use whatever method you are currently using)
[self.navigationController pushViewController:destinationVC animated:YES];
I am able to successfully show the user their current location on a MapView. However when I go to another view controller and come back to my mapview, I see a blue screen. Why?
This is my code:
- (void)viewWillAppear:(BOOL)animated {
MyManager * myManager = [MyManager sharedInstance];
//if coming back from another screen, lets load the coordinates
if (myManager.centerOfMap) {
NSLog(#"myManager.centerOfMap has a value:");
self.centerOfMap = myManager.centerOfMap;
}
CLLocationCoordinate2D zoomLocation;
zoomLocation = *(self.centerOfMap);
MKCoordinateRegion viewRegion = MKCoordinateRegionMakeWithDistance(zoomLocation, 0.5*METERS_PER_MILE, 0.5*METERS_PER_MILE);
MKCoordinateRegion adjustedRegion = [_mapView regionThatFits:viewRegion];
[_mapView setRegion:adjustedRegion animated:YES];
}
A blue screen is often a sign that you're point to (0,0) off the coast of Africa. Try printing out the coordinates of centerOfMap
At the point you come back, is the MKMapView allocated or does it show nil in the debugger?
Not sure? When you come back to your view controller, in the code go ahead and set a breakpoint and, in the console, type "po _mapView". Look at the result.
If it is nil, you probably have to Alloc/Init it. What's probably going on is that ARC is automatically flushing out the MKMapView in order to save memory.
Just a question, are you presenting the new View Controller in a modal way using [yourMainViewController presentViewController:newViewController animated:YES]?
This bit sets off alarm bells:
CLLocationCoordinate2D zoomLocation;
zoomLocation = *(self.centerOfMap);
This presumably corresponds to
#property (nonatomic, assign) CLLocationCoordinate2D * centerOfMap;
Which means it's highly likely that it now points to a random bit of stack, which has since been overwritten. It is highly likely that the high-order word is between 0 and 0x4000000 (0 and a billion - most integers and memory addresses will be in this range), which means you end up with a double between (approximately) 0 and 2.
Get rid of the *.
I have a mutablearray that is populated from sqlite db in ios. I have gotten the annotations to load and view properly. My question is how can I write a loop that will add annotations with the size of the array. I have tried the following code and get and display the last entry in the array
NSMutableArray *annotations=[[NSMutableArray alloc] init];
CLLocationCoordinate2D theCoordinate5;
MyAnnotation* myAnnotation5=[[MyAnnotation alloc] init];
for (int i = 0; i < _getDBInfo.count; i++) {
dbInfo *entity = [_getDBInfo objectAtIndex:i];
NSNumber *numlat=[[NSNumber alloc] initWithDouble:[entity.Latitude doubleValue]];
NSNumber *numlon=[[NSNumber alloc] initWithDouble:[entity.Longitude doubleValue]];
NSLog(#"%d",[_getDBInfo count]);
la=[numlat doubleValue];
lo=[numlon doubleValue];
theCoordinate5.latitude=la;
theCoordinate5.longitude=lo;
myAnnotation5.coordinate=theCoordinate5;
myAnnotation5.title=[NSString stringWithFormat:#"%#"entity.EntityNo];
myAnnotation5.subtitle=[NSString stringWithFormat:#"%#",entity.EntityName];
[mapView addAnnotation:myAnnotation5];
[annotations addObject:myAnnotation5];
}
I guess my question is how can I create and add to my view annotation objects based on the count in my array?
Any help is much appreciated.
I am new to iOS as well as programming so please be gentle.
You only have one myAnnotation5 object. When you set its coordinate, title, etc., you are setting it for that instance, which you happen to have added to annotations multiple times. Hence every entry in annotations will have the last set of properties you set - since every entry in annotations is actually the same object.
To remedy this, you need to create your myAnnotation5 object anew each iteration of the loop, i.e.
for (int i = 0; i < _getDBInfo.count; i++) {
MyAnnotation* myAnnotation5=[[MyAnnotation alloc] init];
...
myAnnotation5.coordinate=theCoordinate5;
myAnnotation5.title=[NSString stringWithFormat:#"%#", entity.EntityNo];
myAnnotation5.subtitle=[NSString stringWithFormat:#"%#", entity.EntityName];
...
[mapView addAnnotation:myAnnotation5];
}
Two asides:
I hope you are building with ARC, otherwise you are leaking memory left and right.
Since MKMapView has an -annotations property, there is likely little reason for you to keep your own annotations array - just keep a reference to mapView.
Move this line:
MyAnnotation* myAnnotation5=[[MyAnnotation alloc] init];
to inside the for-loop just before setting the properties on myAnnotation5.
The way it is right now, you are creating only one MyAnnotation object and modifying its properties repeatedly.