How to get locationManager startMonitoringSignificantLocationChanges accurate readings - iphone

Hi I have a requirement where I need to update user's location to the server while app is running in the background. I have used the code below to test it in the car and have found few discrepancies in the lat and long that are reported when the - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation: is fired.The coordinates are way far of to where I actually am at that moment.
I know the didupdatelocation uses cell tower readings hence not very accurate.I was wondering if there is anyway I can start [locationManager startUpdatingLocation] when the - (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:; and then get the readings which are much more accurate.
Please any help or directions would be great and highly appreciated.
#import "LocationsAppDelegate.h"
#import "RootViewController.h"
#implementation LocationsAppDelegate
#synthesize window;
#synthesize navigationController;
-(void)initLocationManager {
if (locationManager == nil) {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // 100 m
// [locationManager startUpdatingLocation];
[locationManager startMonitoringSignificantLocationChanges];
}
}
- (void)saveCurrentData:(NSString *)newData {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *savedData = [[NSMutableArray alloc] initWithArray:[defaults objectForKey:#"kLocationData"]];
[savedData addObject:newData];
[defaults setObject:savedData forKey:#"kLocationData"];
[savedData release];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSDate* eventDate = newLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
//check if the data is less than 15 sec ago
if (abs(howRecent) > 15.0)
{
NSLog(#"old data latitude %+.6f, longitude %+.6f\n",
newLocation.coordinate.latitude,newLocation.coordinate.longitude);
}else{
[locationManager startUpdatingLocation];
NSDateFormatter * formatter = [[[NSDateFormatter alloc] init] autorelease];
[formatter setTimeStyle:NSDateFormatterMediumStyle];
NSString *locationData = [NSString stringWithFormat:#"%.6f, %.6f, %#",newLocation.coordinate.latitude, newLocation.coordinate.longitude,[formatter stringFromDate:newLocation.timestamp]];
[self saveCurrentData:locationData];
[locationManager stopUpdatingLocation];
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSString *errorData = [NSString stringWithFormat:#"%#",[error localizedDescription]];
NSLog(#"%#", errorData);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if (![CLLocationManager significantLocationChangeMonitoringAvailable]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry" message:#"Your device won't support the significant location change." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
return YES;
}
[self initLocationManager];
[self.window addSubview:navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc {
[locationManager release];
[navigationController release];
[window release];
[super dealloc];
}
#end

The behaviour of startMonitoringSignificantLocationChanges is not affected by the distanceFilter or desiredAccuracy properties.
So if you want to retrieve more accurated results, call startUpdatingLocation, and by playing with the distanceFilter and desiredAccuracy properties (kCLLocationAccuracyBestForNavigation, kCLLocationAccuracyBest) are the most accurated, but consumes more power, so play with them.
I didn't understand exactly the behaviour of your code. Why you call startMonitoringSignificantLocationChanges instead of startUpdatingLocation, but you call it inside the delegate method?

Related

CLLocationManager always locates London

I have the following lines of code to locate my position, but I always get the the same location regardless of where I am:
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[locationManager startUpdatingLocation];
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
self.lati = [NSString stringWithFormat:#"%f",location.coordinate.latitude];
self.longi = [NSString stringWithFormat:#"%f",location.coordinate.longitude];
[locationManager stopUpdatingLocation];
locationManager.delegate = nil;
}
in .h write
<CLLocationManagerDelegate>
then this also
CLGeocoder *geocoder;
CLLocationManager *locationManager;
then in .m
locationManager = [[CLLocationManager alloc] init] ;
locationManager.delegate = self;
[CLLocationManager locationServicesEnabled];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLHeadingFilterNone;
[locationManager startUpdatingLocation];
and then implement its delegates
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation(CLLocation*)newLocation fromLocation:(CLLocation *)oldLocation
{
[manager stopUpdatingLocation];
userCoordinate=newLocation.coordinate;
[[NSUserDefaults standardUserDefaults] setFloat:userCoordinate.latitude
forKey:#"userLat"];
[[NSUserDefaults standardUserDefaults] setFloat:userCoordinate.longitude
forKey:#"userLong"];
CLGeocoder * geoCoder = [[CLGeocoder alloc] init];
[geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
for (CLPlacemark * placemark in placemarks)
{
NSString *cityName = #"";
NSString *countryName = #"";
cityName = [placemark.addressDictionary valueForKey:#"City"];
countryName = [placemark.addressDictionary valueForKey:#"Country"];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setObject:cityName forKey:#"CityName"];
[prefs setObject:countryName forKey:#"CountryName"];
}
}];
[manager stopUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
[manager stopUpdatingLocation];
if(error.code == kCLErrorDenied)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning" message:#"You have to select \"Allow\" for current location." delegate:self cancelButtonTitle:#"Ok"
otherButtonTitles: nil];
alert.tag = 888;
[alert show];
}
[[NSUserDefaults standardUserDefaults] setFloat:0.0
forKey:#"userLat"];
[[NSUserDefaults standardUserDefaults] setFloat:0.0
forKey:#"userLong"];
[manager stopUpdatingLocation];
}
Use this delegate method in place of your delegate method. It will work for you.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
myLatitude = newLocation.coordinate.latitude;
myLongitude = newLocation.coordinate.longitude;
NSLog(#"LAT AND LON IS %f %f",myLatitude,myLongitude);
}

Not getting current user location

in .h file
#import <MapKit/MapKit.h>
#interface FirstViewController : UIViewController <MKMapViewDelegate,MKReverseGeocoderDelegate,CLLocationManagerDelegate>
{
}
in .m file
-(void)viewDidLoad
{
CLLocationManager *locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[super viewDidLoad];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
MKReverseGeocoder *geoCoder = [[MKReverseGeocoder alloc] initWithCoordinate:newLocation.coordinate];
geoCoder.delegate = self;
[geoCoder start];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"locationManager:%# didFailWithError:%#", manager, error);
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
MKPlacemark * myPlacemark = placemark;
NSString *kABPersonAddressCityKey;
NSString *city = [myPlacemark.addressDictionary objectForKey:(NSString*) kABPersonAddressCityKey];
lblAddress.text = city;
NSLog(#"city detail is:--> %#",city);
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
NSLog(#"reverseGeocoder:%# didFailWithError:%#", geocoder, error);
}
This is the code which I have done to get the current location of user & print it in the label.
But the CLLocationManager delegate method (which are written above) is not called & I am not able to get the current address.
Please help me out.
Where I am doing mistake...? guide me.
Thanks.
Instead of autoreleasing the CLLocationManager instance, assign it to an ivar in your class. Then release it in -dealloc as usual (or in one of the delegate methods if you don't need it any longer).
I suspect your location manager is getting deallocated on the next turn of the run loop before having an opportunity to fire off its delegate methods.
In your method viewDidLoad:
-(void)viewDidLoad
{
CLLocationManager *locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
myMapView.showsUserLocation = YES; // add this line
[super viewDidLoad];
}
And you are done!!!

How to update location only when button is pressed

How can I make my application update location only when a button is pressed?
I have a button named "REFRESH". Everytime this button is pressed, I want to show my user their location. For example, 51 Bourke Street, Victoria.
However, I do not want to update my location regularly. I want to update its location only when the button is pressed, to save battery power.
What do you think? Am I doing it correctly?
I have these classes:
VoteViewController.h and VoteViewController.m
CoreLocationController.h and CoreLocationController.m
This is what I have:
VoteViewController.h class
#interface VoteViewController : UIViewController <CoreLocationControllerDelegate>
{
CoreLocationController *coreController;
}
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
- (void)geoReverseAddress:(MKPlacemark *)placeMark;
- (IBAction)refreshButtonPressed;
VoteViewController.m class
- (void)viewDidLoad
{
[super viewDidLoad];
coreController = [[CoreLocationController alloc] init];
coreController.delegate = self;
}
- (IBAction)refreshButtonPressed
{
NSLog(#"Refresh Button pressed");
label.text = [NSString stringWithString:#""];
[coreController.locationManager startUpdatingLocation];
}
- (void)locationUpdate:(CLLocation *)location
{
comments.text = [location description];
[coreController.locationManager stopUpdatingLocation];
}
- (void)locationError:(NSError *)error
{
comments.text = [error description];
[coreController.locationManager stopUpdatingLocation];
}
- (void)geoReverseAddress:(MKPlacemark *)placeMark
{
label.text = [NSString stringWithFormat:#"%# %#, %#", [placeMark subThoroughfare],
[placeMark thoroughfare], [placeMark locality]];
}
CoreLocationController.h class
#protocol CoreLocationControllerDelegate <NSObject>
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
- (void)geoReverseAddress:(MKPlacemark *)placeMark;
#end
#interface CoreLocationController : NSObject <CLLocationManagerDelegate, MKReverseGeocoderDelegate>
{
CLLocationManager *locationManager;
id delegate;
MKReverseGeocoder *reverse;
}
#property(nonatomic, retain) CLLocationManager *locationManager;
#property(nonatomic, retain) id delegate;
#end
CoreLocationController.m class
-(id) init
{
self = [super init];
if (self != nil)
{
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLHeadingFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Update location");
[self.delegate locationUpdate:newLocation];
reverse = [[MKReverseGeocoder alloc] initWithCoordinate:[newLocation coordinate]];
reverse.delegate = self;
[reverse start];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
[reverse cancel];
[reverse release];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
[self.delegate geoReverseAddress:placemark];
[reverse cancel];
[reverse release];
}
When you first fire up CLLocationManager, you're very likely to get one stale location from the last time it ran. Once that's out of the way, you're going to start getting very inaccurate locations while the device uses WiFi sniffing and cell triangulation, while the GPS looks for a fix.
So in your didUpdateToLocation method, you probably want to throw away the first hit, and then test the .horizontalAccuracy value of your newLocation object for a low enough value to trust.
Apart from that, I don't see anything bad about what you've sent here. I'm not sure I'd go to the trouble of wrapping the location fetching work in its own class, I'd probably just do that out in my viewController. But that's a style choice. If you're reusing this functionality elsewhere, what you've got here is obviously the way to go.

MKMapView leaking from autorealease in main.m

I know from this forum that this is a known bug that has been reported to Apple, but I am concerned that the memory leak keeps increasing everytime I call the view.
the relevant code is
-(IBAction)getlocationgo:(id) sender{
//NSAutoreleasePool *pool;
//pool = [[NSAutoreleasePool alloc] init];
self.locationManager=[[[CLLocationManager alloc]init]autorelease];
self.locationManager.delegate = self;
[locationManager startUpdatingLocation];
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//mapView.showsUserLocation =YES;
//[pool release];
}
- (void)locationManager:(CLLocationManager*)aManager didFailWithError:(NSError*)anError
{
switch([anError code])
{
case kCLErrorLocationUnknown: // location is currently unknown, but CL will keep trying
break;
case kCLErrorDenied: // CL access has been denied (eg, user declined location use)
{UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Location Error"
message:#"Please enable Location Services in the Settings menu"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
[alert show];
[alert release];}
break;
case kCLErrorNetwork: // general, network-related error
{UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Location Error"
message:#"The Little Helper can't find you - please check your network connection or that you are not in airplane mode"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
[alert show];
[alert release];}
break;
}
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"thisruns");
MKCoordinateSpan span;
span.latitudeDelta =0.2;
span.longitudeDelta =0.2;
MKCoordinateRegion region;
region.span = span;
region.center = newLocation.coordinate;
[mapView setRegion:region animated:YES];
mapView.showsUserLocation =YES;
mapView.mapType = MKMapTypeHybrid;
latitude.text = [NSString stringWithFormat:#"%f",newLocation.coordinate.latitude];
longitude.text = [NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
NSString *newloc=longitude.text;
NSLog(#"long%f", newloc);
[locationManager stopUpdatingLocation];
}
the property's are with this
#property (nonatomic, retain) CLLocationManager *locationManager;
and it is dealloced
mapView.delegate = nil;
[mapView release];
locationManager.delegate = nil;
[locationManager release];
I have been going back and forward with this for a few days now, any help or tips would be great.
Thank you
Edit One
Trying to access locationManager in the app delegate, everything runs but there is no update to the location from the IBaction
This is the code in the IBaction and the result from the log is (null)
LLHelperAppDelegate *appDelegate = (LLHelperAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.locationManager startUpdatingLocation];
appDelegate.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
NSLog(#"%#", [appDelegate locationManager]);
Whilst as an Apple issue you won't be able to remove the leak entirely, you can definitely stop it from happening every time you trigger getlocationgo. Rather than constantly creating a CLLocationManager, just use a single CLLocationManager in your app's delegate (or create a singleton to support it). That way you'll only alloc/init a location manager once during your app's lifecycle, whereas currently you alloc/init one every time you reload that view / call the getlocationgo method.

How do I get the current location from the location manager?

i want my app to get the exact location (longitude and latitude) of where he is as every second, it is possible ? i have this code so far, every 3 second the app get the current location but it doesnt update if i move...
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
NSLog(#"lol");
[locationManager stopUpdatingLocation];
if (wtf == 2) {
[[NSUserDefaults standardUserDefaults] setObject:newLocation forKey:#"old"];
NSLog(#"wtf");
wtf =0;
}
oldLocation = [[NSUserDefaults standardUserDefaults] objectForKey:#"old"];
double rep = [oldLocation distanceFromLocation:newLocation];
NSString *label1 = [NSString stringWithFormat:#"%2.90f",oldLocation.coordinate.latitude];
NSString *label2 = [NSString stringWithFormat:#"%2.90f",newLocation.coordinate.latitude];
if ([label1 isEqual:label2]) {
NSLog(#"penis");
}
labelm.text = label1;
labelkm.text = label2;
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
}
-(void)actualise{
[locationManager startUpdatingLocation];
}
- (void)viewDidLoad {
[super viewDidLoad];
wtf = 2;
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[NSTimer scheduledTimerWithTimeInterval:3 target:self selector:#selector(actualise) userInfo:nil repeats:YES];
}
/*
Use this code to initialize and start the location manager:
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
[locationManager startUpdatingLocation];
And implement didUpdateToLocation like this:
- (void) locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*) oldLocation
{
// This will be called every time the device has any new location information.
}
There is no need to use any timers.