I am struggling with geolocation on simulator, but recently, I have tested it directly on device (iPhone) but the same issue remains, here is what I got when my app finish launching and the code of geolocation suppose to give me my location on the map (remember the picture above is for my app on iPhone and not with the simulator) :
so for my code, my app actually have a lot of views, but concerning this function, I have worked on the appdelegate(.m and .h) and the view concerning of showing the location on the map (PositionActuelleViewController).
appdelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
sleep(3);
// Override point for customization after application launch.
self.locationManager=[[[CLLocationManager alloc] init] autorelease];
if([CLLocationManager locationServicesEnabled]) {
self.locationManager.delegate=self;
self.locationManager.distanceFilter=100;
[self.locationManager startUpdatingLocation];
}
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
and in the same file after the dealloc method :
#pragma mark CLLocationManagerDelegate Methods
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
MKCoordinateSpan span;
span.latitudeDelta=0.2;
span.longitudeDelta=0.2;
MKCoordinateRegion region;
region.span=span;
region.center=newLocation.coordinate;
[viewCont.mapView setRegion:region animated:YES];
viewCont.mapView.showsUserLocation=YES;
viewCont.latitude.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.latitude];
viewCont.longitude.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
}
my PositionActuelleViewController.m file :
#import "PositionActuelleViewController.h"
#implementation PositionActuelleViewController
#synthesize mapView;
#synthesize latitude;
#synthesize longitude;
-(IBAction)goBackToMenu {
[self dismissModalViewControllerAnimated:YES];
}
-(IBAction)goToRechercherView;
{
rechercherViewController.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:rechercherViewController animated:YES];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[mapView release];
[latitude release];
[longitude release];
[super dealloc];
}
#end
What am I missing here?
Does the delegate method -(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation ever get called? Maybe if you uncomment self.locationManager.distanceFilter=100; it will work because according to docs, distanceFilter property defines the minimum distance (measured in meters) a device must move laterally before an update event is generated.
Related
In my app, I used core location & Mapkit framework with mapview. When wwe install the app,it shows me alert like " would like to use current location" by default without coding for the one time only. And if i select "don't allow", the map view is just shown blue background?? and if i select "ok" then it works fine.
Help me!
my code is follow:
Appdelegate.m
CLLocationManager *locationManager;
CLLocation *userLocation;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
[self createEditableCopyOfDatabaseIfNeeded];
//=========================================Location Manager
if(locationManager == nil)
locationManager =[[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy= kCLLocationAccuracyBest;
self.locationManager.distanceFilter= 5;
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
//==========================================
}
-(void) locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(#"new location");
self.userLocation=newLocation;
NSLog(#"user llocation %f , %f",userLocation.coordinate.latitude,userLocation.coordinate.longitude);
[self.locationManager startMonitoringSignificantLocationChanges];
}
Mapview.h
{
IBOutlet MKMapView *map;
CLLocation *currentLocation;
NSString *specificLatitude;
NSString *specificLongitude;
MKCoordinateRegion region;
}
Mapview.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
[APPDELEGATE.locationManager startUpdatingLocation];
}
- (void)viewWillAppear:(BOOL)animated
{
self.map.delegate = self;
// Ensure that you can view your own location in the map view.
[self.map setShowsUserLocation:YES];
}
-(void)viewDidAppear:(BOOL)animated{
currentLocation =APPDELEGATE.userLocation;
region.center = self.currentLocation.coordinate;
MKCoordinateSpan span;
span.latitudeDelta = 0.05;
span.longitudeDelta = 0.03;
region.span = span;
[map setRegion:region animated:TRUE];
[self searchPressed];
NSLog(#"Mapview %f %f",currentLocation.coordinate.latitude,currentLocation.coordinate.longitude
);
}
If you select "Don't Allow" then call this delegate.
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
//Do something
}
I haven't tried this but maybe you can test to see if it works.
For your view controller that displays your map view, try conforming to the UIAlertViewDelegate.
Then in the alert view delegate callback method, you can do whatever you want, if it works:
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// you need to type the exact title of the alert popup
// button index starts from 0 (left most button), so if the are 2 buttons
// and "Don't allow" button is on the right, the button == 1 is that button
// the user tapped on
if([alertView.title isEqualToString:#"Type Exact Alert Title Here"] && buttonIndex == 1)
{
// do something
}
}
So now I'm at least getting callbacks with the following code...
- (void)viewDidLoad {
[super viewDidLoad];
mapView=[[MKMapView alloc] initWithFrame:self.view.frame];
//mapView.showsUserLocation=TRUE;
mapView.delegate=self;
[self.view insertSubview:mapView atIndex:0];
NSLog(#"locationServicesEnabled: %#", [CLLocationManager locationServicesEnabled] ? #"YES":#"NO");
CLLocationManager *newLocationManager = [[CLLocationManager alloc] init];
[newLocationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[newLocationManager setDistanceFilter:kCLDistanceFilterNone];
[self setLocationManager:newLocationManager];
[[self locationManager] setDelegate:self];
[[self locationManager] startUpdatingLocation];
NSLog(#"Started updating Location");
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"Did update to location");
mStoreLocationButton.hidden=FALSE;
location=newLocation.coordinate;
MKCoordinateRegion region;
region.center=location;
MKCoordinateSpan span;
span.latitudeDelta=0.01;
span.longitudeDelta=0.01;
region.span=span;
[mapView setRegion:region animated:TRUE];
}
I can set breakpoints in the second method and NSLog is reporting continual location updates, but for some reason the zoom with span isn't working. Any idea why? It's got my coordinates and everything. Sort of scratching my head on this one.
Assign the CLLocationManager to a (strong) property on your class. (I assume you're using ARC BTW.) Right now the CLLocationManager doesn't live past the end of the viewDidLoad method, so it won't get to call your delegate method either.
Make sure that you've added <CLLocationManagerDelegate> in the #interface file.
Edit:
If the delegate is set properly, make sure you're using your locationManager property:
In the .h file:
#property (nonatomic, strong) CLLocationManager *locationManager;
In viewDidLoad:
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self];
[self.locationManager startUpdatingLocation];
I think, You can make this work by two ways:
Using CLLocation framework
Check that, you have adopted the ViEWController with CLLocationManagerDelegate methods
#import<MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate,
MKMapViewDelegate>
{
CLLocationCoordinate2D location;
MKMapView *mapView;
}
#end
In ViewController.m:
#implementation GSViewController
- (void)viewDidLoad {
[super viewDidLoad];
mapView=[[MKMapView alloc] initWithFrame:self.view.frame];
mapView.showsUserLocation=TRUE;
mapView.delegate=self;
[self.view insertSubview:mapView atIndex:0];
CLLocationManager *locationManager=[[CLLocationManager alloc] init];
locationManager.delegate=self;
locationManager.desiredAccuracy=kCLLocationAccuracyNearestTenMeters;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(#"new location: %#", newLocation);
location=newLocation.coordinate;
MKCoordinateRegion region;
region.center=location;
MKCoordinateSpan span;
span.latitudeDelta=0.01;
span.longitudeDelta=0.01;
region.span=span;
[mapView setRegion:region animated:TRUE];
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"error: %#", error.description);
}
#end
2.Using the same MKMapKit framework
You can do this by using the MKMapViewDelegate method named didUpdateUserLocation:
Here you don't need the CLLocaionManager,
This will be done by:
In ViewController.h:
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController < MKMapViewDelegate>
{
CLLocationCoordinate2D location;
MKMapView *mapView;
}
#end
and In ViewController.m file:
#implementation GSViewController
- (void)viewDidLoad {
[super viewDidLoad];
mapView=[[MKMapView alloc] initWithFrame:self.view.frame];
mapView.showsUserLocation=TRUE;
mapView.delegate=self;
[self.view insertSubview:mapView atIndex:0];
}
-(void)mapView:(MKMapView *)mapV didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"map new location: %f %f", userLocation.coordinate.latitude, userLocation.coordinate.longitude);
location=userLocation.coordinate;
MKCoordinateRegion region;
region.center=location;
MKCoordinateSpan span;
span.latitudeDelta=0.1;
span.longitudeDelta=0.1;
region.span=span;
[mapV setRegion:region animated:TRUE];
}
#end
Well, first of all, you can never be sure that the location manager is able to update the location in the first place. There could be an error during update or you don't have access to the user's location.
Implement this CLLocationManager delegate method and verify the error.
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
"Implementation of this method is optional. You should implement this method, however."
If you're running this in the simulator only you might need to prompt it to change coordinates. In Xcode there is a bar above the debug output pane with the typical Location Services arrow. Next to that is a drop down list of locations. Once your app is running, switch the location it is simulating and see if that change triggers your code. Then test it on a real device.
In my case, it didn't enter on didChangeAuthorization. I was trying on a real device.
I deleted the application from the phone and install it again. And it works!
Hope this helps someone :)
For Swift 3
The method has changed to:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
from:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [AnyObject]!)
Notice the '_' and the cast of 'locations' to [CLLocation] rather than [AnyObject]!
If you use the old method it will never be called and you won't receive a warning that it has changed.
I am trying to connect to GPS from my code. I am doing so according to this tutorial.
- (void)viewDidLoad {
[super viewDidLoad];
CLController = [[CoreLocationController alloc] init];
CLController.delegate = self;
[CLController.locMgr startUpdatingLocation];
}
- (void)locationUpdate:(CLLocation *)location {
locLabel.text = [location description];
}
- (void)locationError:(NSError *)error {
locLabel.text = [error description];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
The above code is placed in a view controller called GetMyLocationViewController, and I have another view controller called MainScreenViewController.
When the screen loads, the MainScreenViewController gets loaded, and I will need the GPS location to continue operations with this screen.
In the ViewDidLoad method of MainScreenViewController I wrote the following;
- (void)viewDidLoad {
[super viewDidLoad];
GetMyLocationViewController *getMyLocationViewController = [[GetMyLocationViewController alloc]initwithXib:nil bundle:nil];
[self.navigationController pushViewController:getMyLocationViewController Animation:YES];
// AND THEN I NEED TO ACCESS THE LONGITUDE AND LATITUDE VALUES
}
When the above code gets executed, the viewDidLoad method of MainScreenViewController gets executed, but not the locationUpdate method. The only way I could get the values of longitude and latitude is by the execution of locationUpdate method. So how can I get these values?
Do you tested in a device? xcode before the version 4.2 dont have a GPS simulator, because of that the method locationUpdate never call.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if([self.delegate conformsToProtocol:#protocol(CoreLocationControllerDelegate)]) { // Check if the class assigning itself as the delegate conforms to our protocol. If not, the message will go nowhere. Not good.
[self.delegate locationUpdate:newLocation];
}
}
Are you sure you are loading your GetMyLocationViewController? Your code only shows loading the MainScreenViewController, which, in its -viewDidLoad method, loads itself again, which would cause an infinite loop of loading and pushing MainScreenViewControllers.
UPDATE: That CoreLocationController class in the tutorial seems unnecessary. Rather that using it, make CLLocationManager a property of your GetMyLocationViewController. Make GetMyLocationViewController's -viewDidLoad method look like this:
-(void)viewDidLoad {
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
}
don't forget to import the CoreLocation library and implement the delegate methods.
I'm using that code running on an iPhone 4 :
- (id)init
{
self = [super initWithNibName:#"OfflineView" bundle:nil]; // ok, not perfect but for test, that works fine
if (self) {
self.locationMgr = [[CLLocationManager alloc] init];
self.locationMgr.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
self.locationMgr.distanceFilter = kCLDistanceFilterNone;
self.locationMgr.headingFilter = kCLHeadingFilterNone;
self.locationMgr.delegate = self;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// do things
}
// triggered when showing the view, first call here after the init
- (void) start
{
self.view.hidden = NO;
[self.locationMgr startUpdatingLocation];
[self.locationMgr startUpdatingHeading];
}
but the delegate method is not triggered.
It's only triggered when the phone moves.
How may I init my process with a valid user location when the view appears, without asking my user to shake it phone and make a 100m run, before being able to do something ?
You could "prime" it by kicking the delegate method yourself once.
- (void) start
{
self.view.hidden = NO;
[self.locationMgr startUpdatingLocation];
[self.locationMgr startUpdatingHeading];
[self locationManager: self.locationMgr didUpdateToLocation: [self.locationMgr currentLocation] fromLocation: nil];
}
where do you call start:? you should be getting first fix without moving. It's an asynchronous call back so might take time.
Ideally you should be calling startUpdateLocation in the init/viewDidLoad and then read it in locationUpdate:
- (void)locationUpdate:(CLLocation *)location {
// Read location
}
I have been stuck on this for days, and was wondering if anyone had any clues? Should be simple, but it has me stuck! I get my location, then continue. But I want to stay IN THAT METHOD - LOOPING - until I get a valid location. Then loadview. THANKS for any tips!
I am using the standard:
- (id)init
{
if (self = [super init])
{
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // send loc updates to myself
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
}
return self;
}
- (void)viewDidLoad
{
// do my processing here ONLY when I get a valid location***************************
// and if I never get a valid location, then just go to my last location.
}
(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 5.0)
{
[manager stopUpdatingLocation]
printf("latitude %+.6f, longitude %+.6f\n", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
}
}
Rather than spinning in your viewDidLoad, how about putting up a temporary view until you have your GPS location?
// custom full-screen view class of your choice
// could just be a UIImageView if you wanted
SplashOverlay *splash;
- (void)viewDidLoad {
[super viewDidLoad];
splash = [[SplashOverlay alloc] initWithNibName:#"SplashOverlay" bundle:nil];
[self.view addSubview:splash.view];
}
// do this code to get rid of the view
- (void) doneWithSplashScreen {
[splash.view removeFromSuperview];
[splash release];
splash = nil;
}
your view will still be under the splash screen waiting, but nobody can interact with it until you're ready.