I am working on an iOS 6.1 iPhone app with ARC enabled which will be using a CLLocationManager to track the devices position.
UPDATE
I have a DestinationViewController which implements the CLLocationManagerDelegate. It creates the CLLocationManager and does the setup. I have imported the CoreLocation framework to my project.
I have tried to debug a lot and can see that the CLLocationManager is created and no errors are present. But the problem is that the [CLLocationManager authorizationStatus] is kCLAuthorizationStatusNotDetermined
both before [self.locationManager startUpdatingLocation]; and also after.
So there is no prompt about asking permission to use location services for this app. Because of that this method is never fired.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:
(NSArray *)locations
I have also tried to search the web for hours to look for similar examples but with no luck. Code from DestinationViewController is posted below.
Interface
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface DestinationViewController : UIViewController <CLLocationManagerDelegate>
Implementation
#import "DestinationViewController.h"
#interface DestinationViewController ()
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#implementation DestinationViewController
// Initializer
- (CLLocationManager *)locationManager
{
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
}
return _locationManager;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self startLocation];
}
- (void)startLocation
{
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 1;
NSString *error;
if (![CLLocationManager locationServicesEnabled]) {
error = #"Error message";
}
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
if (status == kCLAuthorizationStatusRestricted ||
status == kCLAuthorizationStatusDenied ||) {
error = #"Error message";
}
if (error) {
NSLog(error);
}
else
{
status = [CLLocationManager authorizationStatus];
self.locationManager.pausesLocationUpdatesAutomatically = NO;
[self.locationManager startUpdatingLocation];
status = [CLLocationManager authorizationStatus];
NSLog(#"CLLocationManager is %#", self.locationManager);
NSLog(#"Location is %#", self.locationManager.location);
[self updateUI];
}
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation *recentLocation = [locations lastObject];
NSLog(#"Found location");
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError");
}
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
NSLog(#"Change in authorization status");
}
Your code should work.
Make sure your application is authorized to use location services.
You can use following method to check authorization status in code
+ (CLAuthorizationStatus)authorizationStatus
Edit
kCLAuthorizationStatusNotDetermined is most likely caused by location services being disabled. You should check location services status first. Code should be like this
if([CLLocationManager locationServicesEnabled]) {
// Location Services Are Enabled
switch([CLLocationManager authorizationStatus]) {
case kCLAuthorizationStatusNotDetermined:
// User has not yet made a choice with regards to this application
break;
case kCLAuthorizationStatusRestricted:
// This application is not authorized to use location services. Due
// to active restrictions on location services, the user cannot change
// this status, and may not have personally denied authorization
break;
case kCLAuthorizationStatusDenied:
// User has explicitly denied authorization for this application, or
// location services are disabled in Settings
break;
case kCLAuthorizationStatusAuthorized:
// User has authorized this application to use location services
break;
}
} else {
// Location Services Disabled
}
I finally solved it! My delegate wasn't set properly.
Instead of doing:
self.locationManager.delegate = self;
I changed it to:
[self.locationManager setDelegate:self];
And now my delegate methods get fired.
Thanks to those who helped!
Related
I'm pretty new to iOS development (my first app) and I faced this issue.
I have an iPhone app that should get user's current location in multiple ViewControllers upon user button touch. To prevent redundant code (implementing locationManager:didFailWithError, locationManager:didUpdateToLocation:fromLocation, etc. multiple times in different view controllers) I decided to create a custom class called LocationManager:
LocationManager.h
#interface LocationManager : NSObject <CLLocationManagerDelegate> {
#private
CLLocationManager *CLLocationManagerInstance;
id<LocationManagerAssigneeProtocol> assignee;
}
-(void) getUserLocationWithDelegate:(id) delegate;
LocationManager.m
#implementation LocationManager
-(id)init {
self = [super init];
if(self) {
CLLocationManagerInstance = [[CLLocationManager alloc] init];
CLLocationManagerInstance.desiredAccuracy = kCLLocationAccuracyBest;
CLLocationManagerInstance.delegate = self;
}
return self;
}
-(void) getUserLocationWithDelegate:(id) delegate {
if([CLLocationManager locationServicesEnabled]) {
assignee = delegate;
[CLLocationManagerInstance startUpdatingLocation];
}
}
#pragma CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
...
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[CLLocationManagerInstance stopUpdatingLocation];
[assignee didUpdateToLocation:newLocation];
}
and I have a protocol called LocationManagerAssigneeProtocol that my ViewControllers implement
#protocol LocationManagerAssigneeProtocol <NSObject>
#required
-(void) didUpdateToLocation:(CLLocation *) location;
#end
and in my viewcontroller where needed
- (IBAction)getMyLocation:(id)sender {
[locationMgr getUserLocationWithDelegate:self];
}
This code works perfectly, however, I have a feeling that I'm violating some design patterns here by letting LocationManager be able to call a function of the class that itself initiated a call to Location Manager. On the other hand, I don't want to go with implementing CLLocationManagerDelegate for all my viewcontrollers that are supposed to work with locations.
Are there any better solution to this issue?
I agree with #CarlVeazey on this one. Delegate are great for a 1 to 1 relationship existing at any one time, however in your case it seems that you may need multiple viewControllers to respond to location events at any given time. So just remove anything related to your delegate and its associated protocol.
I'd probably make LocationManager class a singleton and modify the methods for updating:
+(LocationManager *)sharedInstance
{
static LocationManager *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
-(void)getUserLocation
{
if ([CLLocationManager locationServicesEnabled])
[CLLocationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[CLLocationManagerInstance stopUpdatingLocation];
[[NSNotificationCenter defaultCenter] postNotificationWithName:#"LocationManagerDidUpdateLocation" object:newLocation];
}
... Then any viewController that needs to use this class would have something like:
-(void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserverForName:#"LocationManagerDidUpdateLocation" object:self queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
CLLocation *location = note.object;
...
}];
}
-(IBAction)getMyLocation:(id)sender {
[[LocationManager sharedInstance] getUserLocation];
}
Hope that helps and makes sense.
I am doing one application.In that i am using the CLLocationManager Class for getting the updated location latitude and longitude details.But i need to use this CLLocationManager in sepaate thread .I written my code like below.
- (void)viewDidLoad
{
[NSThread detachNewThreadSelector:#selector(fetch) toTarget:self withObject:nil];
}
-(void)fetch
{
manager=[[CLLocationManager alloc]init];
manager.delegate=self;
manager.distanceFilter=kCLDistanceFilterNone;
manager.desiredAccuracy = kCLLocationAccuracyBest;
[manager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"%f",newLocation.coordinate.latitude);
lbl.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
}
.But this delegate method is not fired when i run this code.So please guide me how to get the location updates in separate thread.
The methods of your delegate object are called from the thread in which you started the corresponding location services. That thread must itself have an active run loop, like the one found in your application’s main thread. ——from apple document
Could you please tried with this.
dispatch_async(newThread, ^(void) {
[self fetch];
});
hope you'll get solved problem.
in .h file
MainView *ctl;
NSMutableDictionary *dictSubPoses;
- (id)initWithCtl:(MainView*)_ctl;
in .m file
- (id)initWithCtl:(MainView*)_ctl
{
if(self = [super init])
{
ctl = _ctl; //[_ctl retain];
}
return self;
}
- (void)main
{
[ctl performSelector:#selector(yourMethod) withObject:dictSubPoses];
}
in .h file
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
//Set Delegate
CLLocationManagerDelegate
// Declare
CLLocationManager *locationManager;
in .m file
-(void)ViewDidLoad
{
locationupadate=YES;
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = 100.0f;
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if(locationupadate)
{
NSLog(#"%f",newLocation.coordinate.latitude);
lbl.text=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
}
I was really hesitant to post a fourth question on this subject, but triple-checked everything according to previous answers and still get bad results.
Problem: CLLocationManager does not call didEnterRegion in iOS6.
Setup: iOS6.
Here is the code with all the functions relevant to CLLocationManager
myMapViewController.h
#interface FirstViewController : UIViewController <UIApplicationDelegate,CLLocationManagerDelegate, MKMapViewDelegate, UISearchBarDelegate,RKObjectLoaderDelegate >
{
/* variables */
}
#property (strong, nonatomic) CLLocationManager *locationManager;
myMapViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
/* other initialization code */
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter: kCLLocationAccuracyBest];
[locationManager setDesiredAccuracy: kCLLocationAccuracyBest];
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
/* other application code */
Step* step = [_steps lastObject];
CLRegion *tmpReg = [[CLRegion alloc] initCircularRegionWithCenter:step.start_location.coordinate radius:1000 identifier: [step.start_locationLat stringValue] ];
[locationManager startMonitoringForRegion:tmpReg];
NSLog(#"Setting region with latitude %f", tmpReg.center.latitude);
}
- (void)locationManager:(CLLocationManager *)manager didStartMonitoringForRegion:(CLRegion *)region{
NSLog(#"Monitoring region with latitude %f", region.center.latitude);
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region{
NSLog(#"ENTERED REGION!");
}
}
- (void) locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region{
NSLog(#"EXITED REGION!");
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
NSLog(#"Region monitoring failed with error: %#", [error localizedDescription]);
}
Application runs with zero warnings and here is the log:
2012-12-02 19:31:41.449 myApp[5695:c07] Setting region with latitude 37.785690
2012-12-02 19:31:41.506 myApp[5695:c07] Monitoring region with latitude 37.785690
Have you entered the region? You question doesn't actually say that you are moving your device in and out of the region you are monitoring, or simulating that movement via Xcode.
you did not forget to put [locationManager startUpdatingLocation]; ??
I want to get users current location. Here is my code
// In LoginViewController.h
#interface LoginViewController : UIViewController <UserLocationDelegate,UIAlertViewDelegate> {
CLLocation *usersLocation;
}
#property (nonatomic,strong) CLLocation *usersCurrentLocation;
#end
// In LoginViewController.m
#implementation LoginViewController
#synthesize usersCurrentLocation;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.usersCurrentLocation = nil;
[self currentLocationOfUser];
}
-(void)currentLocationOfUser {
UserLocation *userLocation = [[UserLocation alloc]init];//UserLocation];
userLocation.delegate = self;
[userLocation getCurrentLocationOfUser];
}
#pragma mark - User Location Delegate Methods
- (void)locationUpdate:(CLLocation *)location
{
self.usersCurrentLocation = location;
NSLog(#"Latitude:- %.6f",self.usersCurrentLocation.coordinate.latitude);
NSLog(#"Longitude:- %.6f",self.usersCurrentLocation.coordinate.longitude);
}
- (void)locationError:(NSString *)errorMsg
{
[Common showAlertWithTitle:#"Error" andMessage:errorMsg];
}
// In UserLocation.h
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#protocol UserLocationDelegate <NSObject>
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSString *)errorMsg;
#end
#interface UserLocation : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
__weak id<UserLocationDelegate>delegate;
}
#property (nonatomic,strong) CLLocationManager *locationManager;
#property (nonatomic,weak) id<UserLocationDelegate>delegate;
-(id)initUserLocation;
-(void)getCurrentLocationOfUser;
#end
// In UserLocation.m
#import "UserLocation.h"
#implementation UserLocation
#synthesize locationManager;
#synthesize delegate;
#synthesize geoCodingDelegate;
-(id)initUserLocation
{
if (self == [super init]) {
self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
}
return self;
}
-(void)getCurrentLocationOfUser {
self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
if ([CLLocationManager locationServicesEnabled]) {
//[self.locationManager startMonitoringSignificantLocationChanges];
[self performSelector:#selector(startLocationUpdate) withObject:nil afterDelay:2.0];
}
else {
if ([delegate respondsToSelector:#selector(locationError:)]) {
[self.delegate locationError:#"Please Turn On Location Services in Settings To Retrive User's Current Location"];
}
else {
[Common showAlertWithTitle:#"Error" andMessage:#"Please Turn On Location Services in Settings To Retrive User's Current Location"];
}
}
}
-(void)startLocationUpdate
{
[self.locationManager startMonitoringSignificantLocationChanges];
}
#pragma mark CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if ([delegate respondsToSelector:#selector(locationUpdate:)]) {
[delegate locationUpdate:newLocation];
}
}
-(void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
if ([delegate respondsToSelector:#selector(locationError:)]) {
[delegate locationError:#"Some Error Occured While Retriving Users's Location"];
}
else {
[Common showAlertWithTitle:#"Error" andMessage:#"Some Error Occured While Retriving Users's Location"];
}
}
#end
But it is not returning any location update.
Also its not asking user permission to use location. My app is not listed in Location Services. How can I add my app in Location Serverices ?
What's worong in above code ?
I solved this problem by declaring UserLocation *userLocation in .h & writing property.
Since I am using ARC , its deallocating userLocation so I am not getting location updates.
This is the first time I am using CLLocationManager. I am not sure if i am doing the right thing. Correct me if i am wrong.
I initialize the locationManager in my viewDidLoad Method and tell the locationManager to startUpdatingLocation in the same method.
When the delegate receives
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
[locationManager stopUpdatingLocation];
//do stuff with the coordinates
}
to avoid repeated calls to this delegate method.
I have a UIButton where users can click to update the location
//called by user action
-(IBAction)updateLocation{
//start updating delegate
locationManager.delegate=self;
[locationManager startUpdatingLocation];
}
However when the location changes and when I click the UIbutton, the location coordinates donot change at all. :(
What am i doing wrong? Is this the right of doing or should i not stop the locationManager at all ?
Help would be appreciated.
CLLocationManager caches your last location and returns it as soon as you call -startUpdatingLocation. So, you are starting updates, receiving the old location, and then stopping updates.
This isn't how -startUpdatingLocation/-stopUpdatingLocation are meant to be used. As I asked above, what's wrong with calling the delegate method multiple times? If you only want to get the location when the user taps a button, leave the CLLocationManager updating, and just check CLLocationManger's location property when the user taps your button.
If the reason you're trying to avoid multiple calls to the delegate method is because you're worried about power consumption, etc., adjust the desiredAccuracy property of the CLLocationManager with something like: locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters.
All told, it might look something like this...
.h file:
#interface YourController : NSObject <CLLocationManagerDelegate>
#property (nonatomic, retain) CLLocationManager *locationMgr;
#property (nonatomic, retain) CLLocation *lastLocation;
- (IBAction)getNewLocation:(id)sender;
#end
.m file:
#interface YourController
#synthesize locationMgr = _locationMgr;
#synthesize lastLocation = _lastLocation;
- (id)init
{
if (self = [super init]) {
self.locationMgr = [[CLLocationManager alloc] init];
self.locationMgr.desiredAccuracy = kCLLocationAccuracyBest;
self.locationMgr.delegate = self;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if (!self.lastLocation) {
self.lastLocation = newLocation;
}
if (newLocation.coordinate.latitude != self.lastLocation.coordinate.latitude &&
newLocation.coordinate.longitude != self.lastLocation.coordinate.longitude) {
self.lastLocation = newLocation;
NSLog(#"New location: %f, %f",
self.lastLocation.coordinate.latitude,
self.lastLocation.coordinate.longitude);
[self.locationMgr stopUpdatingLocation];
}
}
- (IBAction)getNewLocation:(id)sender
{
[self.locationMgr startUpdatingLocation];
NSLog(#"Old location: %f, %f",
self.lastLocation.coordinate.latitude,
self.lastLocation.coordinate.longitude);
}
- (void)dealloc
{
[self.locationMgr release];
self.locationMgr = nil;
[self.lastLocation release];
self.lastLocation = nil;
[super dealloc];
}
#end
Am assuming you have included #import <CoreLocation/CoreLocation.h> framework to being with. This is the way you start getting location updates.
CLLocationManager *locationMgr = [[CLLocationManager alloc] init];
locationMgr.desiredAccuracy = kCLLocationAccuracyBest;
locationMgr.delegate = self;
[locationMgr startUpdatingLocation];
You are correct here. After this you start getting location updates, here in this delegate-
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// Handle location updates
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
// Handle error
}