When I configure the CLlocationManager with this code:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
if([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
// Or [self.locationManager requestWhenInUseAuthorization];
} [self.locationManager startUpdatingLocation];
}
and the set the location delegate
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
self.textLongitude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
self.textLatitude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
DonĀ“t send the alert for authorized, but the Info.plist is complete
when go to settings and change in settings -> privacy -> localize and change the status for "always", and restart the app this status is clean.
The NSLocationAlwaysUsageDescription is misspelled in the plist.
Hi I am having trouble using CLLocationManager to find the current user location. Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
}
- (IBAction)pressed:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[locationManager stopUpdatingLocation];
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSLog(#"%.8f", currentLocation.coordinate.longitude);
NSLog(#"%.8f", currentLocation.coordinate.latitude);
}
}
When I run this code, nothing happens at all. There is no reaction in the debugger. As I understand, didUpdateToLocation is deprecated in iOS6 but I thought it was still usable. If anyone can tell me what I am doing wrong or suggest an alternative please let me know. Thanks!
How'd you define stuff in your .h file? I assume like:
#import <UIKit/UIKit.h>
#import <CoreLocation/CLLocationManager.h>
#import <CoreLocation/CLLocationManagerDelegate.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate, CLLocationManagerDelegate>
#property (strong, nonatomic) UIWindow *window;
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
And the main .m file I ran:
#import "AppDelegate.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
return YES;
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[self.locationManager stopUpdatingLocation];
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
NSLog(#"%.8f", currentLocation.coordinate.longitude);
NSLog(#"%.8f", currentLocation.coordinate.latitude);
}
}
Here's the output on the simulated iOS:
2014-08-12 13:36:28.933 tester[5577:60b] Application windows are expected to have a root view controller at the end of application launch
2014-08-12 13:36:35.237 tester[5577:60b] didUpdateToLocation: <+37.78******,-122.40******> +/- 5.00m (speed -1.00 mps / course -1.00) # 8/12/14, 1:36:35 PM Central Daylight Time
2014-08-12 13:36:35.237 tester[5577:60b] -122.40******
2014-08-12 13:36:35.238 tester[5577:60b] 37.78******
I am working with Map Kit in iOS 8 using Obj-C NOT SWIFT. I cannot get the device location it is set a 0.00, 0.00 and I am getting the error:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
I have implemented: ( I have tried only one at a time and no luck )
if(IS_OS_8_OR_LATER) {
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
And in info.plist
NSLocationWhenInUseUsageDescription : App would like to use your location.
NSLocationAlwaysUsageDescription : App would like to use your location.
I do get prompted to allow the app to use my location but after I agree nothing changes. The location is being showed as 0.00, 0.00.
Code for displaying users location:
//Get Location
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
MKCoordinateRegion region = { { 0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = self.locationManager.location.coordinate.latitude;
region.center.longitude = self.locationManager.location.coordinate.longitude;
region.span.longitudeDelta = 0.005f;
region.span.longitudeDelta = 0.005f;
[mapView setRegion:region animated:YES];
Mike.
**EDIT: View Answer Below.
I got it working. I've posted my code below to help anyone else having issues.
Here is my full code to get the MapKit Map View working in iOS 8.
In your AppName-Info.plist
Add a new row with the key name being:
NSLocationWhenInUseUsageDescription
Or
NSLocationAlwaysUsageDescription
With the value being a string of the message that you want to be displayed:
YourAppName would like to use your location.
In your header file. (I use App Name-Prefix.pch but YourViewController.h will work too)
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
YourViewController.h
#import <MapKit/MapKit.h>
#import <MapKit/MKAnnotation.h>
#interface YourViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate> {
}
#property(nonatomic, retain) IBOutlet MKMapView *mapView;
#property(nonatomic, retain) CLLocationManager *locationManager;
YourViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
mapView.delegate = self;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER) {
// Use one or the other, not both. Depending on what you put in info.plist
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
#endif
[self.locationManager startUpdatingLocation];
mapView.showsUserLocation = YES;
[mapView setMapType:MKMapTypeStandard];
[mapView setZoomEnabled:YES];
[mapView setScrollEnabled:YES];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:YES];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
NSLog(#"%#", [self deviceLocation]);
//View Area
MKCoordinateRegion region = { { 0.0, 0.0 }, { 0.0, 0.0 } };
region.center.latitude = self.locationManager.location.coordinate.latitude;
region.center.longitude = self.locationManager.location.coordinate.longitude;
region.span.longitudeDelta = 0.005f;
region.span.longitudeDelta = 0.005f;
[mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation
{
MKCoordinateRegion region = MKCoordinateRegionMakeWithDistance(userLocation.coordinate, 800, 800);
[self.mapView setRegion:[self.mapView regionThatFits:region] animated:YES];
}
- (NSString *)deviceLocation {
return [NSString stringWithFormat:#"latitude: %f longitude: %f", self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceLat {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.latitude];
}
- (NSString *)deviceLon {
return [NSString stringWithFormat:#"%f", self.locationManager.location.coordinate.longitude];
}
- (NSString *)deviceAlt {
return [NSString stringWithFormat:#"%f", self.locationManager.location.altitude];
}
Enjoy!
--Mike
It's not written anywhere, but if your app starts with MapKit, you will still receive the error message "Trying to start MapKit location updates without prompting for location authorization" even after implementing MBarton's answer. To avoid it, you have to create a new view controller before the MapKit, and implement the location manager delegates there. I called it AuthorizationController.
So, in AuthorizationController.h:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface MCIAuthorizationController : UIViewController <CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
And in AuthorizationController.m:
- (void)viewDidLoad {
[super viewDidLoad];
// Location manager
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
}
#pragma mark - Location Manager delegates
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
NSLog(#"didUpdateLocations: %#", [locations lastObject]);
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Location manager error: %#", error.localizedDescription);
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[self.locationManager startUpdatingLocation];
[self performSegueWithIdentifier:#"startSegue" sender:self];
} else if (status == kCLAuthorizationStatusDenied) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Location services not authorized"
message:#"This app needs you to authorize locations services to work."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
} else
NSLog(#"Wrong location status");
}
Try This One:
(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
self.mapView.showsUserLocation = YES;
}
Your code looks fine, though you do not need to call requestWhenInUseAuthorization and the other requestAlwaysAuthorization , choose one you need.
Code for displaying locations is just yet allocating locationManager, do not expect to get location data instantly.
you need to wait till delegate method gets called :
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
, then self.locationManager.location will also be set.
Further to Mikes answer, I found that using both [self.locationManager requestWhenInUseAuthorization]; and [self.locationManager requestAlwaysAuthorization]; as demonstrated in his code does not work. You should only use ONE.
I assume some further changes were made with a more recent/stable version of the API.
I had the same problem but adding these two line in plist file solved my problems
NSLocationWhenInUseUsageDescription
And
NSLocationAlwaysUsageDescription
NOTE : Must provide string description of both these values. You can use any of them in your controller file as below
self.locationManager= [[CLLocationManager alloc] init];
self.locationManager.delegate=self;
[self.locationManager requestAlwaysAuthorization];
You must implement CLLOcationManagerDelegate in your controller to access this functionality
To extend the accepted answer and if you create a sample project with just the above functionality, then apart from CoreLocation and Mapkit frameworks, you might need to add UIKit, Foundation and CoreGraphics framework manually as well in Xcode 6.
Actually, I am studying the CS193P Lecture 16, which is about location and map view, and I could not make the location manager work in iOS 8, applying what was in the video.
Looking at your answer, I could make it work.
The Info.plist was modified as described in the answers (I use the NSLocationWhenInUseUsageDescription).
In AddPhotoViewController.hn the define was added :
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
In AddPhotoViewController.m, the following code was added in ViewDidLoad (after self.image):
#ifdef __IPHONE_8_0
if(IS_OS_8_OR_LATER)
{
[self.locationManager requestWhenInUseAuthorization];
}
#endif
The authorization will be asked only once, the first time you launch the application.
The following was also added to AddPhotoViewController.h because it was not said in Lecture 16 :
#property (nonatomic) NSInteger locationErrorCode;
shouldPerformSegueWithIdentifier was modified to include else if (!self.location) :
else if (![self.titleTextField.text length])
{
[self alert:#"Title required"];
return NO;
}
else if (!self.location)
{
switch (self.locationErrorCode)
{
case kCLErrorLocationUnknown:
[self alert:#"Couldn't figure out where this photo was taken (yet)."]; break;
case kCLErrorDenied:
[self alert:#"Location Services disabled under Privacy in Settings application."]; break;
case kCLErrorNetwork:
[self alert:#"Can't figure out where this photo is being taken. Verify your connection to the network."]; break;
default:
[self alert:#"Cant figure out where this photo is being taken, sorry."]; break;
}
return NO;
}
else
{ // should check imageURL too to be sure we could write the file
return YES;
}
didFailWithError was added :
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
self.locationErrorCode = error.code;
}
I want to make an app that gives me an Enter & Exit alert message for current position with 10 meters radius. Here is my code:
-(void)startLocationServices
{
if (self.locationManager == nil)
{
self.locationManager = [CLLocationManager new];
}
[self.locationManager setDelegate:self];
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:kCLDistanceFilterNone];
[self.locationManager startUpdatingLocation];
}
-(void)stopLocationServices
{
[self.locationManager stopUpdatingLocation];
[self.locationManager setDelegate:nil];
//self.locationUpdateTextView.text = #"Location Service stop";
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self startLocationServices];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
self.locationUpdateTextView.text = [#"New Location: \n\n" stringByAppendingFormat:#"%# \n \nCurrent Position\nLatitude: %f \nLongitude: %f", [locations lastObject], self.locationManager.location.coordinate.latitude, self.locationManager.location.coordinate.longitude];
CLLocationCoordinate2D center = CLLocationCoordinate2DMake(locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude);
CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:center radius:10.0 identifier:#"Test"];
[self.locationManager startMonitoringForRegion:region];
[self stopLocationServices];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Status" message:#"You Enter the region" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alertView show];
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Status" message:#"You Exit the region" delegate:self cancelButtonTitle:#"ok" otherButtonTitles:nil, nil];
[alertView show];
}
- (void) locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
self.availabilityTextView.text = [#"\nError:" stringByAppendingFormat:#"%#", error];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
I call [self stopLocationServices]; in didUpdateLocations method so that it grabs the user's current position, set the radius and then stop. When I run the app and move 10 meters it is not giving any alert message though I cross the 10 meters radius. Rather, I get it randomly especially when I restart the app after crossing the 10 meters radius. I know the cell tower issue in this case, but I am not sure my thinking is accurately workable in this scenario. If anyone understands my problem and knows any solution please share that with me.
Problem is location manager is not updating location.
The (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLoc fromLocation:(CLLocation *)oldLoc functions gets called but it displays the new location as the same old location.
Following is my piece of code:
In my viewDidLoad method i am creating the object of CLLocationManager
-(void) viewDidLoad
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
// created a timer to call locationUpdate method
[NSTimer scheduledTimerWithTimeInterval:20 target: self selector: #selector(locationUpdate) userInfo: nil repeats: YES];
}
-(void)locationUpdate
{
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLoc
fromLocation:(CLLocation *)oldLoc
{
NSLog(#"in locationmanager did update %f",newLoc.coordinate.latitude);
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance(newLoc.coordinate, 0.01, 0.02);
[self.mapView setRegion:region animated:YES];
[self.locationManager stopUpdatingLocation];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
MKCoordinateSpan span = MKCoordinateSpanMake(0.01, 0.02);
MKCoordinateRegion region = MKCoordinateRegionMake(mapView.userLocation.coordinate, span);
[_mapView setRegion:region animated:YES];
[_mapView regionThatFits:region];
}
The value which i am getting in NSLog(#"in locationmanager did update %f",newLoc.coordinate.latitude) is always the same even-though i had moved for more than 2 kilometers starting from current location.
Please help me to how to get exact new location whenever there is a locationupdate. Thanks in advance.
You are stopping the location manager with
[self.locationManager stopUpdatingLocation];
in
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLoc
fromLocation:(CLLocation *)oldLoc
. This delegate method gets called EVERY time the user moves and can give you old (cached) data at the beginning, so by stopping it right away when you get your first location fix you probably get a cached location each time. The fix is simple, just don't stop the location manager there but rather when your viewController disappears or at a similar useful place.