iOS 5, waiting for location - ios

I have this method for locate the user and then change some numbers according to the Country he's in:
- (void) localizing {
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
DbOperations *dbOp = [[DbOperations alloc] init];
geoCoder = [[CLGeocoder alloc] init];
[self.geoCoder reverseGeocodeLocation: locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
countryCode = [placemark.addressDictionary valueForKey:#"CountryCode"];
country = [placemark.addressDictionary valueForKey:#"Country"];
NSString *s2 = NSLocalizedString(#"You're currently in %#", nil);
lblLocation.text = [NSString stringWithFormat:s2, self.country];
[dbOp UsefulNumbers:self.countryCode];
NSUserDefaults *loc = [NSUserDefaults standardUserDefaults];
[loc setObject:country forKey:#"Country"];
[loc setObject:countryCode forKey:#"CountryCode"];
[loc synchronize];
}];
[locationManager stopUpdatingLocation];
NSUserDefaults *loc = [NSUserDefaults standardUserDefaults];
if ([loc objectForKey:#"Country"] == NULL) {
btnUno.enabled = NO;
btnDue.enabled = NO;
btnTre.enabled = NO;
lblLocation.text = NSLocalizedString(#"Unable to locate you", nil);
}
}
The method get called by 'viewDidLoad' method but the very first time I run the app I can't get located.
If I open up Maps, let it get the fix and then open my app, everything goes fine.
I thought that maybe I don't give enough time to the app to get a GPS fix or maybe I'm just doing it wrong.
Any suggestions?
EDIT: modified the code, not working yet.
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
}
return self;
}
- (void) viewDidLoad {
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
[locationManager startUpdatingLocation];
[super viewDidLoad];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
DbOperations *dbOp = [[DbOperations alloc] init];
geoCoder = [[CLGeocoder alloc] init];
[self.geoCoder reverseGeocodeLocation: locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
//Get nearby address
CLPlacemark *placemark = [placemarks objectAtIndex:0];
//String to hold address
countryCode = [placemark.addressDictionary valueForKey:#"CountryCode"];
country = [placemark.addressDictionary valueForKey:#"Country"];
NSString *s2 = NSLocalizedString(#"You're currently in %#", nil);
lblLocation.text = [NSString stringWithFormat:s2, self.country];
[dbOp UsefulNumbers:self.countryCode];
NSUserDefaults *loc = [NSUserDefaults standardUserDefaults];
[loc setObject:country forKey:#"Country"];
[loc setObject:countryCode forKey:#"CountryCode"];
[loc synchronize];
NSLog(#"Country: %#", country);
}];
NSUserDefaults *loc = [NSUserDefaults standardUserDefaults];
if ([loc objectForKey:#"Country"] == NULL) {
btnUno.enabled = NO;
btnDue.enabled = NO;
btnTre.enabled = NO;
lblLocation.text = NSLocalizedString(#"unable to locate", nil);
}
}
Method locationManager:didUpdateToLocation:fromLocation does not get called.

You should put your code for reverse geocoding in the delegate method for CLLocationManager:
– locationManager:didUpdateToLocation:fromLocation:
Your current setup is trying to reverse geocode a location before an update has been dispatched from the location manager.
Consider setting up your CLLocationManager in your init method and then waiting for the delegate to be called before attempting to reverse geocode anything.

Related

How to get location at AppDelegate, and pass the lat and long to another VC and load webview

Edited
I have managed to get a current location by using this. After that I am trying to pass lat and long as a string to another method that loads a webview. A problem is every time I load this VC, it doesn't call a following method
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
and straight away jump to the following method.
-(void)viewWillAppear:(BOOL)animated
How do I get a location first and store it an variables, pass them to another method as a string, append a string and pass it to NSURL and load a webview?
Is a lat and long retained? How do I retain it throughout my project?
What happens when I click on other tab controller and click back on this VC. Does a lat and long be refreshed again?
- (void)viewDidLoad
{
[super viewDidLoad];
geocoder = [[CLGeocoder alloc] init];
if (locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
[locationManager requestAlwaysAuthorization];
}
[locationManager startUpdatingLocation];
dtDate = [[NSMutableArray alloc] init];
self.currentPageIndex = 0;
self.hasAppearedFlag = NO;
}
//=== It doesn't call a following method first.
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
CLLocation *newLocation = [locations lastObject];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
latitude = [NSString stringWithFormat:#"%f",newLocation.coordinate.latitude];
longitude = [NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
state = placemark.administrativeArea;
country = placemark.country;
NSLog(#"This is the latitude%#", latitude);
NSLog(#"This is the longitude%#", longitude);
} else {
NSLog(#"This is the error debug%#", error.debugDescription);
}
}];
// Turn off the location manager to save power.
[manager stopUpdatingLocation];
//*** It will start loading this part below
[self setupSegmentButtons];
NSDate *now = [NSDate date];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"dd/MM/YYYY"];
NSString *dateString = [dateFormatter stringFromDate:now];
[self LoadClasses:dateString];
self.hasAppearedFlag = YES;
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Cannot find the location.");
}
//=== Load webview
- (void)LoadClasses : (NSString *)sDate{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
sMemCode = [defaults objectForKey:#"txtMemCode"];
NSLog(#"Load Class This is the memCode:%#", sMemCode);
NSLog(#"Load Class This is the latitude:%#", latitude);
NSLog(#"Load Class This is the longitude:%#", longitude);
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
sURL = appDelegate.gURL;
sURL = [sURL stringByAppendingString:#"/apps/class.asp?"];
sURL = [sURL stringByAppendingString:#"memCode="];
sURL = [sURL stringByAppendingString:sMemCode];
sURL = [sURL stringByAppendingString:#"&dtpClass="];
sURL = [sURL stringByAppendingString:sDate];
sURL = [sURL stringByAppendingString:#"&lat="];
sURL = [sURL stringByAppendingString:latitude];
sURL = [sURL stringByAppendingString:#"&long="];
sURL = [sURL stringByAppendingString:longitude];
NSLog(#" The sURL to load for the current page : %# ", sURL);
NSURL *url = [NSURL URLWithString:sURL];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
[webView loadRequest:urlRequest];
[webView setDelegate:(id<UIWebViewDelegate>)self];
}
Solution
I have put the `Location Delegates` to `AppDelegates`
AppDelegates.h
#import <UIKit/UIKit.h>
#import<CoreLocation/CoreLocation.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>{
CLLocationManager *locationManager;
}
#property (nonatomic, strong) NSString *slatitude;
#property (nonatomic, strong) NSString *slongitude;
#end
AppDelegates.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//--- Get current location ---
if (locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
//-- Pop up authrorization to use current location ---
[locationManager requestAlwaysAuthorization];
}
[locationManager startUpdatingLocation];
}
- (void)locationManager: (CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation: (CLLocation *)oldLocation
{
float latitude = newLocation.coordinate.latitude;
slatitude = [NSString stringWithFormat:#"%f",latitude];
float longitude = newLocation.coordinate.longitude;
slongitude = [NSString stringWithFormat:#"%f", longitude];
NSLog(#"App:This is the latitude%#", slatitude);
NSLog(#"App:This is the longitude%#", slongitude);
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Cannot find the location.");
}
In any VC,
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
latitude = appDelegate.slatitude;
longitude = appDelegate.slongitude;
I would suggest you move your code of Location Delegates to your Appdelegate File, so that it registers and keeps updating to the location delegate methods,
You can either make two property variabled from your appdelegate file and keep updating them as the delegate is called or make a getter or setter method something like this:
#interface AppDelegate : UIResponder<UILocationDelegate>{
CLLocationManager * locationManager;
}
#property (nonatomic, strong) NSString *lattitude;
#property (nonatomic, strong) NSString *longitude;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
if (locationManager == nil)
{
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
[locationManager requestAlwaysAuthorization];
}
[locationManager startUpdatingLocation];
}
and then Implement the location delegate method here itself as
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (error == nil && [placemarks count] > 0) {
placemark = [placemarks lastObject];
self.latitude = [NSString stringWithFormat:#"%f",newLocation.coordinate.latitude];
self.longitude = [NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
state = placemark.administrativeArea;
country = placemark.country;
NSLog(#"This is the latitude%#", latitude);
NSLog(#"This is the longitude%#", longitude);
}
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Cannot find the location.");
}
Late you can access this from your ViewController as
- (void)viewDidAppear:(BOOL)animated {
AppDelegate* appdelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSString *lat = appdelegate.lattitude;
NSString *long = appdelegate.longitude;
}
In this manner even if you switch tab bars or change controllers, you will still have the latest locations.
Actually You are calling your method in ViewWillAppear and you are getting data in didUpdateLocations .. There is no guarntee that ViewWillappear will call after that,, better you call your method from didUpdateLocations after you recieve the data

When I fetch location of device, it always shows location set on Edit scheme of Xcode using Corelocation framework in ios

I am checking on device not on simulator and I want to fetch user's current location but it always shows location which I have set in edit scheme field from target of Xcode. I am using below code:
- (void)CurrentLocationIdentifier
{
//---- For getting current gps location
// locationManager = [CLLocationManager new];
locationManager=[[CLLocationManager alloc]init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
if(kCLAuthorizationStatusDenied)
{
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//currentLocation = [locations objectAtIndex:0];
currentLocation=[locations lastObject];
NSLog(#"location:%#",currentLocation);
[locationManager stopUpdatingLocation];
//[locationManager startUpdatingLocation];
geocoder = [[CLGeocoder alloc] init] ;
[geocoder reverseGeocodeLocation:currentLocation completionHandler:^(NSArray *placemarks, NSError *error)
{
if (!(error))
{
placemark = [placemarks objectAtIndex:0];
NSLog(#"\nCurrent Location Detected\n");
NSString *Country = [[NSString alloc]initWithString:placemark.ISOcountryCode];
NSString *state =[[NSString alloc]initWithString:placemark.administrativeArea];
//NSString *state =placemark.administrativeArea;
NSLog(#"%#",Country);
NSLog(#"administrativeArea>>%#",state);
self.stateLabel.text=state;
//[locationManager stopUpdatingLocation];
[[NSUserDefaults standardUserDefaults]setValue:Country forKey:#"countryISOCode"];
}
else
{
}
}];
[locationManager stopUpdatingLocation];
}
How to fetch exact country and state information of user?

Getting location update after certain distance (5 m in my case)

I am taking input of distance filter from user. For testing purpose I am taking it to be 5 m. But I am getting no location updates after walking 5 m. I am testing it on iPhone simulator 5s.
MainScreenController.m
#interface MainScreenController ()
#property (strong, nonatomic) IBOutlet UITextField *txtTakeDistance;
-(void)writeToTextFile : (NSArray<CLLocation *> *) location;
-(void)ShowContentlist;
#end
#implementation MainScreenController
{
//CLLocation *location;
CLLocationManager *locationManager;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
locationManager = [[CLLocationManager alloc]init];
}
- (IBAction)btnSetDistance:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters; // Tried every accuracy option
locationManager.pausesLocationUpdatesAutomatically = NO;
locationManager.distanceFilter = [_txtTakeDistance.text doubleValue];
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"didFailWithError: %#", error);
UIAlertController *controller = [UIAlertController alertControllerWithTitle:#"Error" message:#"Failed to fecth current location" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"OK" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
[controller addAction:okAction];
[self presentViewController:controller animated:YES completion:nil];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
CLLocation *currentLoaction;
currentLoaction = [locations lastObject];
if(locations != nil){
NSLog(#"--> : %#",locations);
[self writeToTextFile:locations];
}
[locationManager stopUpdatingLocation];
}
-(void)writeToTextFile : (NSArray<CLLocation *> *) location{
NSFileManager *fileManager = [NSFileManager defaultManager];
CLLocation *currentLocation;
currentLocation = [location lastObject];
NSDateFormatter *timeFormat = [[NSDateFormatter alloc] init];
[timeFormat setDateFormat:#"yyyy-MM-DD HH:mm:ss"];
NSString *timeStamp = [timeFormat stringFromDate:currentLocation.timestamp];
NSString *content = [NSString stringWithFormat:#"\n%f|%f|%#\n",currentLocation.coordinate.latitude,currentLocation.coordinate.longitude,timeStamp];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDir = [paths objectAtIndex:0];
if ([fileManager fileExistsAtPath:documentDir]==YES) {
NSString *documentFile = [documentDir stringByAppendingPathComponent:#"log.txt"];
NSString *textFromFile = [NSString stringWithContentsOfFile:documentFile encoding:NSUTF8StringEncoding error:nil];
NSString *textToFile = [textFromFile stringByAppendingString:content];
[textToFile writeToFile:documentFile atomically:YES encoding:NSUTF8StringEncoding error:nil];
}else{
NSLog(#"No such file");
}
}
Do correct me if I am doing it in wrong way. All the suggestions are appreciated. Thank you.
Make some change in your code like:
- (IBAction)btnSetDistance:(id)sender {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.pausesLocationUpdatesAutomatically = NO;
locationManager.distanceFilter =5;
if ([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
}
[locationManager startUpdatingLocation];
}
and most important thing is,you can not check how much distance you moved by moving mac.
you should check it on your device.
Try this code
- (IBAction)btnSetDistance:(id)sender
{
locationManager=[[CLLocationManager alloc] init];
locationManager.delegate=self;
if (([locationManager respondsToSelector:#selector(requestWhenInUseAuthorization)]))
{
[locationManager requestWhenInUseAuthorization];
}
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = 5; // change it according to need
[locationManager startUpdatingLocation];
}
with this line locationManager.distanceFilter = 5; every 5 meter distance if you cover map will update
To get the updated Latitude and Longitudes use this code
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation* location = [locations lastObject];
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
double lat = location.coordinate.latitude;
double longi = location.coordinate.longitude;
if (abs(howRecent) < 15.0)
{
NSLog(#"%f,%f",lat,longi);
[locationManager stopUpdatingLocation];
}
}

ioS Google map v2 not working - my location cannot be got

I am working on iOS app using Google Map SDK. I try to set on the CLLocationManager to get location of my device for 10 seconds and right bottom button to get my location instantly. When it comes to the implementation, the app show no response to initiate the method startUpdatingLocation to get my location. Would you please tell me the way to use locationManager to finish the aim?
The following is my working :
-(bool)isNetworkAvailable
{
SCNetworkReachabilityFlags flags;
SCNetworkReachabilityRef address;
address = SCNetworkReachabilityCreateWithName(NULL, "www.apple.com" );
Boolean success = SCNetworkReachabilityGetFlags(address, &flags);
CFRelease(address);
bool canReach = success
&& !(flags & kSCNetworkReachabilityFlagsConnectionRequired)
&& (flags & kSCNetworkReachabilityFlagsReachable);
return canReach;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// [self getTime];
if (![CLLocationManager locationServicesEnabled]) {
NSLog(#"Please enable location services");
return;
}
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
NSLog(#"Please authorize location services");
return;
}
if([self isNetworkAvailable]){
NSLog(#"connected ");
}else {
NSLog(#"not connected ");
}
CarArray = [[NSMutableArray alloc] init];
GMSMarker *marker = [[GMSMarker alloc] init];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
float latitide = [defaults floatForKey:#"lati"];
float longitude = [defaults floatForKey:#"longi"];
NSString *desp = [defaults objectForKey:#"desp"];
NSLog(#"assadsd arrived map");
if(latitide!=0.00&&longitude!=0.00) {
CLLocationCoordinate2D position = CLLocationCoordinate2DMake(latitide, longitude);
marker.position = CLLocationCoordinate2DMake(position.latitude, position.longitude);
camera = [GMSCameraPosition cameraWithLatitude:latitide longitude:longitude zoom:12];
}else{
camera = [GMSCameraPosition cameraWithLatitude:22.2855200 longitude:114.1576900 zoom:12];
marker.position = CLLocationCoordinate2DMake(22.2855200, 114.1576900);
}
if(desp.length > 0 ){
marker.title = desp;
}
self.locationManager = [[CLLocationManager alloc]init];
self.locationManager.delegate = self;
[self.locationManager requestWhenInUseAuthorization];
[self.locationManager requestAlwaysAuthorization];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest ;
self.locationManager.distanceFilter = 5.0f;
mapView_ = [GMSMapView mapWithFrame:CGRectZero camera:camera];
marker.snippet = #"HK";
marker.map = mapView_;
mapView_.mapType = kGMSTypeSatellite;
mapView_.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
mapView_.myLocationEnabled = YES;
});
mapView_.settings.compassButton = YES;
mapView_.settings.myLocationButton = YES;
[mapView_ addObserver:self
forKeyPath:#"myLocation"
options:NSKeyValueObservingOptionNew
context:NULL];
self.view = mapView_;
[self.locationManager startUpdatingLocation];
NSLog(#"assadsd configured d map");
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
NSLog(#"Please authorize location services");
return;
}
NSLog(#"CLLocationManager error: %#", error.localizedFailureReason);
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"application_name", nil) message:NSLocalizedString(#"location_error", nil) delegate:nil cancelButtonTitle:NSLocalizedString(#"ok", nil) otherButtonTitles:nil];
[errorAlert show];
return;
}
-(void) handleDoubleTap {
NSLog(#"location double tap ");
}
-(UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
// CLLocationDelegate
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations{
// Optional: check error for desired accuracy
CLLocation* location = [locations lastObject];
NSLog(#"location x : %f" , location.coordinate.longitude);
NSLog(#"location y : %f" , location.coordinate.latitude);
NSDate* eventDate = location.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
[manager allowDeferredLocationUpdatesUntilTraveled:CLLocationDistanceMax timeout:10];
if (markera == nil) {
markera = [[GMSMarker alloc] init] ;
markera.position = CLLocationCoordinate2DMake( location.coordinate.latitude , location.coordinate.longitude );
markera.groundAnchor = CGPointMake(0.5f, 0.97f); // Taking into account walker's shadow
markera.map = mapView_;
}else {
markera.position = location.coordinate;
}
GMSCameraUpdate *move = [GMSCameraUpdate setTarget:location.coordinate zoom:17];
[mapView_ animateWithCameraUpdate:move];
}

CLLocationManager SignificantLocationChanges Force Refresh

I have an app that uses CLLocation manager and I need ability to force a location event to be delivered. Apple documentation states...
After returning a current location fix, the receiver generates update events only when a significant change in the user’s location is detected. For example, it might generate a new event when the device becomes associated with a different cell tower. It does not rely on the value in the distanceFilter property to generate events. Calling this method several times in succession does not automatically result in new events being generated. Calling stopMonitoringSignificantLocationChanges in between, however, does cause a new initial event to be sent the next time you call this method.
So I read that as I can call stopMonitoringSignificantLocationChanges and then startMonitoringSignificantLocationChanges and receive a location event, however, in practice this is not working. See code below (I've removed pieces so as to not disclose private reverse geo APIs). This is a wrapper class to combine reverse geo with CLLocationManager. In my demo app I am calling beginMonitoringSignificantChanges and then stopMonitoringSignificantChanges and I am only seeing -(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations called when I change locations or when I first install the app, not when I stop and start. Any thoughts?
//
// TTGeoWrapper.m
// LocationManagementDemoApp
//
// Created by Kyle Jurick on 12/17/12.
// Copyright (c) 2012 Kyle Jurick. All rights reserved.
//
#import "TTGeoWrapper.h"
#import "OpenXML.h"
#implementation TTGeoWrapper
-(id)initWith//removed code
{
self = [super init];
if (self) {
//removed code
_transactionTimeout=30;
//removed code
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
authorizationStatus = [CLLocationManager authorizationStatus];
if (authorizationStatus != kCLAuthorizationStatusAuthorized) {
ableToMonitorLocation = false;
}
else
{
ableToMonitorLocation = true;
}
}
return self;
}
-(void)dealloc
{
locationManager.delegate = nil;
}
-(void)beginMonitoringSignificantChanges
{
//if (ableToMonitorLocation) {
[locationManager startMonitoringSignificantLocationChanges];
/*}
NSMutableDictionary *requestFailureUserInfo = [[NSMutableDictionary alloc] init];
[requestFailureUserInfo setValue:#"NOT AUTHORIZED" forKey:#"FAILURE REASON"];
[requestFailureUserInfo setValue:[NSString stringWithFormat:#"%d", authorizationStatus] forKey:#"FAILURE REASON"];
NSError *requestFailure = [[NSError alloc] initWithDomain:#"TTGeoWrapper" code:0 userInfo:requestFailureUserInfo];
[_delegate requestDidFail:requestFailure TTGeoWrapper:self];*/
}
-(void)stopMonitoringSignificantChanges
{
[locationManager stopMonitoringSignificantLocationChanges];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
//per Apple documentation, the last item in the array is the most current location
//http://developer.apple.com/library/ios/#documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/CLLocationManagerDelegate/CLLocationManagerDelegate.html
int latestPollIndex = locations.count-1;
CLLocation *location = [locations objectAtIndex:latestPollIndex];
_timeStamp = location.timestamp;
CLLocationCoordinate2D coordinate = [location coordinate];
[self updateLocationWithLatAsync:coordinate.latitude Long:coordinate.longitude];
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus: (CLAuthorizationStatus)status
{
if (status != kCLAuthorizationStatusAuthorized) {
ableToMonitorLocation = false;
}
authorizationStatus = status;
}
-(NSString *)updateLocationWithLatAsync:(float)latitude Long:(float)longitude;
{
webRequest = [ASIHTTPRequest requestWithURL:[[NSURL alloc] initWithString:_URL]];
[webRequest setDelegate:self];
[webRequest setTimeOutSeconds:_transactionTimeout];
[self buildPacketLat:latitude Long:longitude];
PostGUID = [self generateUuidString];
[self getPostResponseAsync];
return PostGUID;
}
-(NSString *)updateLocationWithLatSync:(float)latitude Long:(float)longitude
{
webRequest = [ASIHTTPRequest requestWithURL:[[NSURL alloc] initWithString:_URL]];
[webRequest setDelegate:self];
[webRequest setTimeOutSeconds:_transactionTimeout];
[self buildPacketLat:latitude Long:longitude];
PostGUID = [self generateUuidString];
[self getPostResponse];
return PostGUID;
}
-(void)buildPacketLat:(float)latitude Long:(float)longitude
{
//removed code
[webRequest appendPostData:[requestXML dataUsingEncoding:NSASCIIStringEncoding]];
}
- (NSString *)generateUuidString
{
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
CFStringRef str = CFUUIDCreateString(kCFAllocatorDefault, uuid);
NSString *uuidString = (__bridge NSString *)str;
CFRelease(uuid);
CFRelease(str);
return uuidString;
}
-(void)getPostResponse
{
NSLog(#"Beginning Synchronous POST");
[webRequest startSynchronous];
}
-(void)getPostResponseAsync
{
NSLog(#"Beginning Asynchronous POST");
[webRequest startAsynchronous];
}
-(void)cancelAsyncRequest
{
NSLog(#"Cancelling Asynchronous POST");
[webRequest cancel];
}
-(void)requestFinished:(ASIHTTPRequest *)request
{
OpenXML *geoResponse = [[OpenXML alloc] initWithData:[request responseData]];
_LocationToXMLString = [geoResponse openXMLToString];
_LocationToOpenXML = geoResponse;
//removed code
else
{
NSMutableDictionary *requestFailureUserInfo = [[NSMutableDictionary alloc] init];
//removed code
NSError *requestFailure = [[NSError alloc] initWithDomain:#"TTGeoWrapper" code:0 userInfo:requestFailureUserInfo];
[_delegate requestDidFail:requestFailure TTGeoWrapper:self];
}
}
-(void)requestFailed:(ASIHTTPRequest *)request
{
NSError *requestFailure = [request error];
[_delegate requestDidFail:requestFailure TTGeoWrapper:self];
}
#end
Apparently, this works only if you re-init CLLocationManager each time too. The documentation does not seem to support that, but my testing certainly does. If someone has a better answer, I would love to hear it.
You are right. Only a re-init of the CLLocationManager will cause the SignificantLocationChanges update for to occur. If you need a fresh location update, then why not use standard location service? Using the standard you also get a much more accurate fix.

Resources