Can we show user location in offline in MKMapview - gps

Can we get current user location "That blue ball which is animating" when our device is offline.when i tried to get current user location and log it i'm getting 0.00000 for both longitude and latitude here is the code that i used to get current user location.I'm using ipad mini to test it.I have also added CLLocationManagerDelegate in .h file.
- (void)viewDidLoad {
[self getUserLocation];
self.myMapView.showsUserLocation = YES;
}
-(void)getUserLocation{
if ([CLLocationManager locationServicesEnabled]) {
locationManager = [[[CLLocationManager alloc] init] autorelease];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[locationManager startUpdatingLocation];
}else{
NSLog(#"User location Disabled");
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentGPSLocation = newLocation;
if (currentGPSLocation != nil) {
currentLocation.latitude = self.myMapView.userLocation.coordinate.latitude;
currentLocation.longitude = self.myMapView.userLocation.coordinate.longitude;
currentLocationWalk.latitude=self.myMapView.userLocation.coordinate.latitude;
currentLocationWalk.longitude=self.myMapView.userLocation.coordinate.longitude;
NSLog(#"didUpdateToLocation: %f,%f", self.myMapView.userLocation.coordinate.latitude,self.myMapView.userLocation.coordinate.longitude);
statusLabel.textColor = [UIColor blackColor];
statusLabel.text = [NSString stringWithFormat:#"%f",self.myMapView.userLocation.coordinate.latitude];
statusLabel1.text = [NSString stringWithFormat:#"%f",self.myMapView.userLocation.coordinate.longitude];
}
}

You are not using ARC (I strongly suggest using it, it avoid most of the memory management errors!).
Therefore it might be that "locationManager" is a instance variable that is not retained (maybe you did not declare it as a retained property).
In this case, it might have been released already when your code returns to the main run loop, where the autorelease pool is drained.

This line
locationManager = [[[CLLocationManager alloc] init] autorelease];
is not a good idea.
define the locationManager as a property,
init the locationManager in viewDidLoad(), but remove the autorelease!
and relase the locationManager only when the viewController is unloaded (there where you release the other properties)

Related

CLLocationManager updateLocation never called while app is in background

I've read so many question here at stackoverflow and I am still having issues with CLLocationManager.I have already added keys in info.plist (NSLocationAlwaysAndWhenInUseUsageDescription,NSLocationWhenInUseUsageDescription,NSLocationAlwaysAndWhenInUseUsageDescription). My app supports ios 9.0 to 11.x.
Update:- I'm testing on iphone6 ios 11.0.3 physical device
My Approach -
1. Start updating location after while using the app permission.
2. When app goes into background stop location manager to remove Blue Banner (Banner Of Shame)
3.Fire a periodic timer of 30 seconds and start location manager again.
This time I never got the delegate callback didUpdateLocation
I have a singleton class called LocationManager.
Here is my code from LocationManager and AppDelegate
LocationManager
- (void)startLocatingUser {
//Locate User
_locationMeasurements = [NSMutableArray array];
self.geocoder = [[CLGeocoder alloc] init];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.pausesLocationUpdatesAutomatically = NO;
self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
if ([self.locationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)]) {
[self.locationManager setAllowsBackgroundLocationUpdates:YES];
}
if(IS_OS_8_OR_LATER) {
if ([self.locationManager respondsToSelector:#selector(requestAlwaysAuthorization)]) {
[self.locationManager requestAlwaysAuthorization];
}
}
if (#available(iOS 11.0, *)) {
self.locationManager.showsBackgroundLocationIndicator = NO;
}
[self.locationManager startUpdatingLocation];
}
- (void)stopLocatingUser {
if(self.locationManager) {
[self.locationManager stopUpdatingLocation];
}
}
AppDelegateCode
- (void)applicationWillResignActive:(UIApplication *)application {
_isBackgroundMode = YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
LocationManager* locationManager = [LocationManager sharedLocationManager];
[locationManager stopLocatingUser];
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
self.bgTimer = [NSTimer scheduledTimerWithTimeInterval:30.0
target:self
selector:#selector(startTrackingBg)
userInfo:nil
repeats:YES];
}
-(void)startTrackingBg {
dispatch_async(dispatch_get_main_queue(), ^{
LocationManager* locationManager = [LocationManager sharedLocationManager];
[locationManager startLocatingUser];
});
NSLog(#"App is running in background");
}
I am never getting this delegate callback in background once I stop and start location manager again.
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
What I simply want is whenever user puts the app in background. I want to hide the banner of shame and then I need periodic location updates in background and send them to server.

How to get shared instance of location manger in synchronize

Hy, I want to get the background location updates, so I wrote the below code and make it synchronized to keep it safe from multithreading. So I have two questions:
Do I really need to synchronize the piece of code, all I am doing in App is just running background task? I never created any special NSThread type to support multithreading and don't require as such?
Whenever I need to start the location updates, I call like this:
CLLocationManager *locationManager = [LocationTracker sharedLocationManager];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
Is correct way to call?
+ (CLLocationManager *)sharedLocationManager {
static CLLocationManager *_locationManager;
#synchronized(self) {
if (_locationManager == nil) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[_locationManager requestAlwaysAuthorization];
_locationManager.distanceFilter = 10;
if(IS_OS_9_OR_LATER){
_locationManager.allowsBackgroundLocationUpdates = YES;
}
}
}
return _locationManager;
}
Shared instance should be synchronised. You can use #Synchronized or dispatch_once. It is good practice to synchronised the shared instances even you are not using the multiple threads.
+ (instancetype)sharedLocationManager {
static LocationTracker *sharedInstance_ = NULL;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance_ = [[LocationTracker alloc] init];
[sharedInstance_ initialize];
});
return sharedInstance_;
}
- (void)initialize {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
[_locationManager requestAlwaysAuthorization];
_locationManager.distanceFilter = 10;
if(IS_OS_9_OR_LATER){
_locationManager.allowsBackgroundLocationUpdates = YES;
}
}
You can implement the location manager delegates inside the LocationTracker class. Use NSNotificationObserver to update all the classes, which are all expecting location update.
Else follow the below line.
CLLocationManager *locationManager = [LocationTracker sharedLocationManager].locationManager;
locationManager.delegate = self;
[locationManager startUpdatingLocation];

How do I get GPS to get my co-ordinates every time I click the button?

I'm creating an app that allows a user to take a picture and receive GPS co-ordinates that coincide with the pictures location, displayed in a label in the cameraView. The picture, time/date and GPS location is then transferred to another view for the user to put a title and description and allows them to save the event. A pop-up alerts them it was saved, and when they click save, the view transfers back to the camera view, where the fields are now clear and ready for the next picture.
My issue is that when the user goes back to the camera view, or even stays on the first view and wants to take multiple pictures, no more GPS co-ordinates are put in the label? I can't figure out why. It's like it only can happen once?
I set the cameraView up so when the user clicks the button, coordinates are retrieved every time?
Here is my mainView.h file on the first controller
//labels for the camera view values
IBOutlet UILabel *DateTimeText;
IBOutlet UILabel *LongitudeText;
IBOutlet UILabel *LatitudeText;
NSData *image;
NSData *passBackImage;
Here is the mainView.m file
//When the user hits the "take a picture button"
-(IBAction)onMoreSnapsClick:(id)sender{
UIImagePickerController *pickerControl = [[UIImagePickerController alloc] init];
// If all's good, start up the camera
if (pickerControl != nil)
{
pickerControl.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerControl.delegate = self;
pickerControl.allowsEditing = true;
// Camera turns on
[self presentViewController:pickerControl animated:true completion:nil];
//Retrieve co-ordinates when picture is taken
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//Format date
_date = [[NSDateFormatter alloc] init];
[_date setDateFormat:#"dd-MM-yyyy HH:mm"];
//Date into a string
_dateString = [_date stringFromDate:[NSDate date]];
[self->DateTimeText setText:_dateString];
[_date stringFromDate:[NSDate date]];
//Update the location
[locationManager startUpdatingLocation];
}
}
- (NSString*) getDateTime
{
NSDateFormatter *formatter;
formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"dd-MM-yyyy HH:mm"];
_dateString = [formatter stringFromDate:[NSDate date]];
return _dateString;
}
//Setting up the delegate for the location finder
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:
(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"didUpdateToLocation: %#", newLocation);
CLLocation *currentLocation = newLocation;
_snapLatitude =[NSString stringWithFormat:#"%.8f",currentLocation.coordinate.latitude];
_snapLongitude =[NSString stringWithFormat:#"%.8f",currentLocation.coordinate.longitude];
if (currentLocation != nil) {
LongitudeText.text = _snapLatitude;
LatitudeText.text = _snapLongitude;
}
}
//Also attached to my button-clears the fields of the previous picture coords
-(IBAction)onClick:(UIButton*)sender
{
DateTimeText.text = nil;
LongitudeText.text =nil;
LatitudeText.text = nil;
_cameraMainView = nil;
}
//Creating the objects for the images
- (void)imagePickerController:(UIImagePickerController *)pickerControl
didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//When finished, access the stored images
_cameraMainView = [info objectForKey:#"UIImagePickerControllerOriginalImage"];
image = UIImagePNGRepresentation(_cameraMainView);
// if everything's okay......
if (_cameraMainView != nil)
// assign the images to the properties
{
_imageView.image = _cameraMainView;
// allow editing and create the delegate
pickerControl.delegate = self;
pickerControl.allowsEditing = true;
}
[pickerControl dismissViewControllerAnimated:true completion:nil];
}
-(IBAction)snapsDetails:(id)sender
{
[self performSegueWithIdentifier:#"snapSegue" sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"snapSegue"])
{
SnapAddTextViewController *toSnapView = segue.destinationViewController;
toSnapView.timeDate = _dateString;
toSnapView.snapViewLongitude = _snapLongitude;
toSnapView.snapViewLatitude =_snapLatitude;
toSnapView.snapActualImage =[[UIImage alloc] initWithData:image];
}
}
Can someone tell me why it will only takes one set of coordinates with the first picture taken and none after that? I am still in school and appreciate the leniency on code structure and neatness.I usually pretty it up as things fall together correctly, thanks.a

CLLocationManager not updating location

Problem is location manager is not updating location.
The (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLoc fromLocation:(CLLocation *)oldLoc functions gets called but it displays the new location as the same old location.
Following is my piece of code:
In my viewDidLoad method i am creating the object of CLLocationManager
-(void) viewDidLoad
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
// created a timer to call locationUpdate method
[NSTimer scheduledTimerWithTimeInterval:20 target: self selector: #selector(locationUpdate) userInfo: nil repeats: YES];
}
-(void)locationUpdate
{
[self.locationManager startUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLoc
fromLocation:(CLLocation *)oldLoc
{
NSLog(#"in locationmanager did update %f",newLoc.coordinate.latitude);
MKCoordinateRegion region =
MKCoordinateRegionMakeWithDistance(newLoc.coordinate, 0.01, 0.02);
[self.mapView setRegion:region animated:YES];
[self.locationManager stopUpdatingLocation];
}
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>) annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
{
MKCoordinateSpan span = MKCoordinateSpanMake(0.01, 0.02);
MKCoordinateRegion region = MKCoordinateRegionMake(mapView.userLocation.coordinate, span);
[_mapView setRegion:region animated:YES];
[_mapView regionThatFits:region];
}
The value which i am getting in NSLog(#"in locationmanager did update %f",newLoc.coordinate.latitude) is always the same even-though i had moved for more than 2 kilometers starting from current location.
Please help me to how to get exact new location whenever there is a locationupdate. Thanks in advance.
You are stopping the location manager with
[self.locationManager stopUpdatingLocation];
in
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLoc
fromLocation:(CLLocation *)oldLoc
. This delegate method gets called EVERY time the user moves and can give you old (cached) data at the beginning, so by stopping it right away when you get your first location fix you probably get a cached location each time. The fix is simple, just don't stop the location manager there but rather when your viewController disappears or at a similar useful place.

didUpdateToLocation called multiple

i have an iOS application witch uses the current location of the user. I am doing like this :
-(void)startGeoloc{
NSLog(#"start geoloc");
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy=kCLLocationAccuracyHundredMeters;
[locationManager startUpdatingLocation];
}
#pragma mark - CLLocationManagerDelegate methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[locationManager stopUpdatingLocation];
AppDelegate *apDelegate =(AppDelegate *)[UIApplication sharedApplication].delegate;
apDelegate.modeGeoloc = YES;
[self callWebService:locationManager.location];
}
The problem of this, is that my method callWebService:locationManager.location is called twice and i would like to call it just one time. how i can i do this ? thanks for your answers
To ensure locationManager only calls the "didUpdate..." method once, use a BOOL to reference if the location has been found yet.
Create the ivar BOOL:
#property BOOL didFindLocation;
Before locationManager startUpdatingLocation, set the new BOOL to NO. That way you can call for a new location update at will.
-(void) startFindingLocation {
self.didFindLocation = NO; // like this
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self]
[locationManager setDesiredAccuracy:kCLLocationAccuracyHundredMeters];
[locationManager startUpdatingLocation];
}
In "didUpdateLocations", check for it.
- (void) locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (!self.didFindLocation) {
self.didFindLocation = YES;
[locationManager stopUpdatingLocation];
// do the rest of your stuff
}
}
If possible, do not set didFindLocation anywhere else in your code to avoid confusion.
locationManager delegate methods can be called very frequently (they didUpdateToLocation all the time, right? :)
One way would be to have your callWebService have state, know whether it is currently executing a request and ignore concurrent requests if one is still going. Another way would be to keep a timestamp and only allow it through if 2 minutes has passed since the previous one.
Had the same problem.
I think the easiest solution is setting the CLLocationManager to null.
locationManager = nil;
after calling
[locationManager stopUpdatingLocation];
locationManager.startUpdatingLocation() fetch location continuously and didUpdateLocations method calls several times,
Just set the value for locationManager.distanceFilter value before calling locationManager.startUpdatingLocation().
As I set 100 meters(you can change as your requirement) working fine, and will work for you.
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 100
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()