I'm creating an app that uses core location and this is my code:
the .h :
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController
<CLLocationManagerDelegate>
#property(strong,nonatomic) CLLocationManager *manager;
#end
the .m :
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController ()
#end
#implementation ViewController
#synthesize manager;
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (!self.manager)
{
self.manager=[CLLocationManager new];
}
self.manager.delegate = self;
self.manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[self.manager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation * currentLocation = (CLLocation *)[locations lastObject];
NSLog(#"Location: %#", currentLocation);
if (currentLocation != nil)
{
NSLog([NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude]);
NSLog([NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude]);
}
}
#end
the problem is didUpdateToLocation is not being called.
I tried putting a breakpoint inside of it and nothing happened.
For iOS location tracking to work correctly, here are the prerequisites, and the order is of importance, too:
Define your class as CLLocationManagerDelegate.
Instantiate CLLocationManager instance.
Set its delegate to self.
Set its various properties (accuracy etc)
Call [CLLocationManagerDelegate startUpdatingLocation] when you intend to.
Listen to location updates within your delegate method didUpdateLocations, implemented within the class designated as CLLocationManagerDelegate.
With your code, here are the things you need to correct:
-(IBAction)submit
{
[self.manager startUpdatingLocation];
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (!self.manager)
{
self.manager=[CLLocationManager new];
}
self.manager.delegate = self;
self.manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
}
In short, before telling it to start updating location, you need to instantiate it and set its properties right. Currently you are doing it the reverse way.
UPDATE
Also, your delegate method didUpdateToLocation is deprecated since iOS 6. You must replace it with newer method, like this:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation * currentLocation = (CLLocation *)[locations lastObject];
NSLog(#"Location: %#", currentLocation);
if (currentLocation != nil)
{
self.latitude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
self.longitude.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
}
}
You need to add these keys to your Info.plist:
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
And also request for the type you want to authorise if iOS8:
if ([self.locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)])
{
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
So the system will display the alert "Allow "app" to access your location...? Allowing will start your location manager and didUpdateLocations will be called.
Related
I am developing an application in Xcode 7.3 for iphone 9.3.3 in Objective-C. I followed the suggestions found on this site -- http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/ to get the iphone's location. I am testing what I have so far using an iphone 9.3.3 over lightning cable.
I have "NSLocationWhenInUseUsageDescription" added to the plist with a value of "Request Location".
I am confused as to why this isn't working. I am not getting any strings with the location over NSLog.
Any help is highly appreciated.
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController<CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (weak, nonatomic) CLLocationManager *locations;
//
//#property (weak, nonatomic) IBOutlet UILabel *longitudelabel;
//#property (weak, nonatomic) IBOutlet UILabel *latitudelabel;
#end
ViewController.m
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "ViewController.h"
#interface ViewController ()
{
NSUserDefaults *defaults;
}
#end
#implementation PollenViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// ** Don't forget to add NSLocationWhenInUseUsageDescription in MyApp-Info.plist and give it a string
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// 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];
}
[self.locationManager startUpdatingLocation];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
// Location Manager Delegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"%#", [locations lastObject]);
}
#end
With iOS 8, requesting permission and beginning to use location services are now separate actions. Since
requestWhenInUseAuthorization
and
requestAlwaysAuthorization
methods runs asynchronously, the app can't start the location services immediately. Instead, you need to implement
locationManager:didChangeAuthorizationStatus
delegate method as follows, which fires any time the authorization status changes based on user input.
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status == kCLAuthorizationStatusAuthorizedAlways
|| status == kCLAuthorizationStatusAuthorizedWhenInUse) {
[manager startUpdatingLocation];
}
}
If the user has previously given permission to use location services, the delegate method will also be called after the location manager is initialized and has its delegate set with the appropriate authorization status as follows
CLLocationManager *manager = [CLLocationManager new]
Manager.delegate = self;
if [CLLocationManager locationServicesEnabled] {
[manager startUpdatingLocation];
}
I have been able to get the location and display it in the app with the following code for ViewController.m. #DuncanC's comment helped alot. This also includes the reverse geocoding.
-Used NSLocationWhenInUseUsageDescription in the Info.plists with String "Need Location".
-Made sure Settings->Privacy->Location Services->AppName was set to "While Using" not "Never".
Hope this is helpful to anyone who's stuck.
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#import "CoreLocation/CoreLocation.h"
#interface ViewController ()
{
NSUserDefaults *defaults;
NSString *locationfound;
}
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#implementation PollenViewController {
CLGeocoder *geocoder;
CLPlacemark *placemark;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//implement location finder
self.locationManager=[[CLLocationManager alloc] init];
self.locationManager.delegate=self;
self.locationManager.desiredAccuracy=kCLLocationAccuracyBest;
//initialize geocoder for later
geocoder = [[CLGeocoder alloc] init];
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
//CURRENTLY WORKING LOCATION MANAGER
//roughly based on ---/*https://gist.github.com/paulw11/84b18044942e2ceea52a8*/
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:
(CLAuthorizationStatus)status {
defaults = [NSUserDefaults standardUserDefaults];
NSLog(#"Callback");
NSLog(#"status %i",status);
if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) {
NSLog(#"Authorized");
[self.locationManager startUpdatingLocation];
} else if (status == kCLAuthorizationStatusDenied || status == kCLAuthorizationStatusRestricted) {
NSLog(#"Denied");
locationfound=[NSString stringWithFormat:#"No Location Found"];;
self.LocationLabel.text=locationfound;
}else{
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
}
}
// Location Manager Delegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *newLocation = [locations lastObject];
NSLog(#"Location new %#",newLocation) ;
// Reverse Geocoding
NSLog(#"Resolving the Address");
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
defaults = [NSUserDefaults standardUserDefaults];
// NSLog(#"Found placemarks: %#, error: %#", placemarks, error);
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
locationfound= [NSString stringWithFormat:#"%#, %#",
placemark.locality,
placemark.administrativeArea];
NSLog(#"%#",locationfound);
self.LocationLabel.text=locationfound;
} else {
NSLog(#"%#", error.debugDescription);
locationfound=[NSString stringWithFormat:#"No Location Found"];;
self.LocationLabel.text=locationfound;
}
} ];
}
#end
You could try
- (void)locationManager:(CLLocationManager*) manager didFailWithError:(NSError*)error
To see if the update is failing and why
I am trying to make a simple app the will get the users longitude and latitude
I followed the tutorial here:
http://www.appcoda.com/how-to-get-current-location-iphone-user/
and came with this:
.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface ViewController : UIViewController <CLLocationManagerDelegate>
#property (strong, nonatomic) IBOutlet UILabel *longitudeLabel;
#property (strong, nonatomic) IBOutlet UILabel *latitudeLabel;
- (IBAction)getCurrentLocation:(id)sender;
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
{
CLLocationManager *locationManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
locationManager = [[CLLocationManager alloc] init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)getCurrentLocation:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
_longitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
_latitudeLabel.text = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
#end
My issue is that "Would like to use your current location" popup.
and none of the delegate methods are being hit, at all. I put a break point at the beginning of each delegate method and nothing. Please help.
Please ensure you have following keys in your info.plist:
NSLocationAlwaysUsageDescription with value I need Location
NSLocationWhenInUseUsageDescription with value I need Location
privacy - location usage description with value I need Location
Ensure the info.plist details as answered earlier and then add the below code during your initialization;
if (IS_OS_8_OR_LATER) {
[locationmanager requestWhenInUseAuthorization];
//or (as per your app requirement)
[locationmanager requestAlwaysAuthorization];
}
I'm trying to use core location in iOS 8 simulator, for that I added in my view an object of type 'MapKit View', In tab Atributtes inspector is checked the option show user location, In my project I'm using ARC, below is the structure of my code:
ViewController.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
#interface MeuPrimeiroViewController : UIViewController <MKMapViewDelegate, CLLocationManagerDelegate>{
IBOutlet MKMapView *mapView;
}
#property (nonatomic, strong) CLLocationManager *locationManager;
#end
ViewController.m
#synthesize locationManager;
- (void)viewDidLoad {
[super viewDidLoad];
if ([CLLocationManager locationServicesEnabled]) {
NSLog(#"CLLocationManager locationServicesEnabled == ON");
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
// Check for iOS 8 Vs earlier version like iOS7.Otherwise code will
// crash on ios 7
if ([locationManager respondsToSelector:#selector
(requestWhenInUseAuthorization)]) {
[locationManager requestAlwaysAuthorization];
}
[locationManager startUpdatingLocation];
}else{
NSLog(#"CLLocationManager locationServicesEnabled == OFF");
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(#"It works this method is called");
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"Error: %#",[error description]);
}
In my info.plist file I add this key (NSLocationAlwaysUsageDescription) with this value (String).
If I go to attributes inspector and enable the checkbox (shows user location) I receive this error message, and core location methods are not called:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
If I disable the checkbox, this message disappear, and core location methods not called again. I try to change the navigation to londom, try to change location to free run but nothing I tried worked, the methods do not continue to be called and never showed an empowering message to use core location. I believe I've already tried everything, anyone have any suggestions or a solution to this problem?
This is what i am doing for my app and working perfectly
- (void)startSignificantChangeUpdates {
if (nil == self.locationManager) {
self.locationManager = [[CLLocationManager alloc] init];
}
self.locationManager.delegate = self;
[self.locationManager startMonitoringSignificantLocationChanges];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
CLLocation* location = [locations lastObject];
if (location) {
self.currentLocation = location;
NSString *latitude = [NSString stringWithFormat:#"%f", location.coordinate.latitude];
NSString *longitude = [NSString stringWithFormat:#"%f", location.coordinate.longitude];
self.latLong = [NSString stringWithFormat:#"%#,%#",latitude, longitude];
}
if (!self.geocoder)
self.geocoder = [[CLGeocoder alloc] init];
[self.geocoder reverseGeocodeLocation:location completionHandler:
^(NSArray* placemarks, NSError* error){
if ([placemarks count] > 0) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
if (placemark.postalCode) {
self.currentZipCode = placemark.postalCode;
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"zipCodeFoundNotification" object:self.currentZipCode userInfo:nil];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:#"zipCodeFoundNotification" object:nil userInfo:nil];
}
}];
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
if (status != kCLAuthorizationStatusAuthorized && status != kCLAuthorizationStatusNotDetermined) {
if (status == kCLAuthorizationStatusDenied){
self.currentZipCode = #"kCLAuthorizationStatusDenied";
} else if (status == kCLAuthorizationStatusRestricted) {
self.currentZipCode = #"kCLAuthorizationStatusRestricted";
}
}
}
I've heard time and time again that there is always a better pattern than the singleton, but I can't understand how else my application could access the device location without waiting for the GPS to return data (I'm assuming that the location system is only running when explicitly called for, correct me if wrong).
So is there a better pattern for accessing CLLocation data from multiple (unrelated) controllers? Or can I expect the device location to be updating in the background even if I am not accessing it through a CLLocationManager?
Declare a single class . Like the following .
MyLocation.h
#protocol MyCLControllerDelegate <NSObject>
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface MyLocation : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
id delegate;
}
#property (nonatomic, strong) CLLocationManager *locationManager;
#property (nonatomic, strong) id <MyCLControllerDelegate> delegate;
MyLocation.m
#import "MyLocation.h"
#implementation MyLocation
#synthesize locationManager;
#synthesize delegate;
- (id) init {
self = [super init];
if (self != nil) {
if([CLLocationManager locationServicesEnabled]) {
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied || [CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted )
{
[self showAlertWithTitle:#"Warning" andWithMessage:#"Determining your current location cannot be performed at this time because location services are enabled but restricted" forTargetView:self];
NSlog(#"Determining your current location cannot be performed at this time because location services are enabled but restricted");
}
else
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self; // send loc updates to myself
[self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.locationManager setDistanceFilter:kThresholdDistance];
[self.locationManager startUpdatingLocation];
NSLog(#"Location sharing set ON!");
}
} else {
[MobileYakHelper showAlertWithTitle:#"Error" andWithMessage:#"Determining your current location cannot be performed at this time because location services are not enabled." forTargetView:self];
NSLog(#"Location sharing set OFF!");
}
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSDictionary *dictValue = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithDouble:newLocation.coordinate.latitude], #"latitude",
[NSNumber numberWithDouble:newLocation.coordinate.longitude], #"longitude",
nil];
[[NSUserDefaults standardUserDefaults] setValue:dictValue forKey:#"MY_LOCATION"];
CLLocationDistance meters = [newLocation distanceFromLocation:oldLocation];
if (meters >= kThresholdDistance ) {
[self.delegate locationUpdate:newLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
}
#end
To use it in few controller .Adapt delegate in it's .h file and use like as follows :
- (void) initializeLocations
{
MyLocation _myLocation = [[MyLocation alloc] init];
_myLocation.delegate = self;
_myLocation.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
CLLocation * currentLocation = _myLocation.locationManager.location;
// Updating user's current location to server
[self sendUserCurrentCoordinate:currentLocation.coordinate];
// start updating current location
_myLocation.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[_myLocation.locationManager startUpdatingLocation];
[_myLocation.locationManager startUpdatingLocation];
}
- (void)locationUpdate:(CLLocation *)location {
NSLog(#"location %#", location);
}
- (void)locationError:(NSError *)error {
NSLog(#"locationdescription %#", [error description]);
}
I was trying to implement a separate class for managing my location. I wanted to get my location whenever I click a button.
gpsFilter.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#interface gpsFilter : NSObject <CLLocationManagerDelegate>
#property (nonatomic, retain) CLLocationManager *gpsManager;
#property (nonatomic, retain) NSString * latitude;
#property (nonatomic, retain) NSString * longitude;
#end
gpsFilter.m.
#import "gpsFilter.h"
#implementation gpsFilter
- (id) init{
self = [super init];
if(self != nil){
self.gpsManager = [[CLLocationManager alloc] init];
self.gpsManager.delegate = self;
[self.gpsManager startUpdatingLocation];
BOOL enable = [CLLocationManager locationServicesEnabled];
NSLog(#"%#", enable? #"Enabled" : #"Not Enabled");
}
return self;
}
- (void)gpsManager:(CLLocationManager *) manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
if(currentLocation != nil){
self.latitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
self.longitude = [NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
}
- (void)gpsManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
}
#end
I am using a separate class because I wanted to add smoothing filter in the future. I don't get any updates. The NSLog is never triggered. I think some variable is getting autoreleased, but I am not sure, which one.
The viewController code is as follows.
#import "gpstestViewController.h"
#interface gpstestViewController (){
}
#end
#implementation gpstestViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.location = [[gpsFilter alloc] init];
// Do any additional setup after loading the view, typically from a nib.
}
- (IBAction)getloca:(id)sender {
self.latitudeLabel.text = [self.location latitude];
self.longitudeLabel.text = [self.location longitude];
}
- (IBAction)getLocation:(id)sender {
self.latitudeLabel.text = [self.location latitude];
self.longitudeLabel.text = [self.location longitude];
}
#end
I am sorry that I am dumping a lot of code, but I am a newbie to ios programming and I am not able to find what the problem is.
EDIT: The updateLocation delegate method is not being called at all.
The delegate methods must be named locationManager:didUpdateToLocation:fromLocation: and locationManager:didFailWithError:.
You cannot use custom method names like gpsManager:didUpdateToLocation:fromLocation:.
Also note that locationManager:didUpdateToLocation:fromLocation: is deprecated as of iOS 6 and you should use locationManager:didUpdateLocations:.
The signature of your didUpdateToLocation is wrong:
This is my code:
/** Delegate method from the CLLocationManagerDelegate protocol. */
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// here do
}
Further set the desiredAccuracy to CLLocationAccuracyBest.