startMonitoringForRegion is not sending to didEnterRegion or didExitRegion - ios

I have a location based app, all though the region is correct the app never moves to didEnterRegion or didExitRegion
for (int x = 0; x <= [[[TaskStore sharedStore] allTasks]count]-1; x++)
{
NSArray *tasks = [[TaskStore sharedStore] allTasks];
Task *selectedTask = [tasks objectAtIndex:x];
location.latitude = selectedTask.locationCoord.coordinate.latitude;
location.longitude = selectedTask.locationCoord.coordinate.longitude;
NSString* desiriedLoc = [selectedTask locationName];
CLRegion *region = [[CLRegion alloc] initCircularRegionWithCenter: location radius: 30.0 identifier: desiriedLoc];
NSLog(#"Entered new Location in Region %#", region);
[locManager startMonitoringForRegion:region];
}
-(void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(#"didEnterRegion for %#",region.identifier);
UIAlertView *alr=[[UIAlertView alloc] initWithTitle:#"Reminder didEnterRegion"
message:region.identifier delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Ok",nil];
[alr show];
}
-(void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"didExitRegion for %#",region.identifier);
UIAlertView *alr=[[UIAlertView alloc] initWithTitle:#"Reminder didExitRegion" message:region.identifier delegate:nil cancelButtonTitle:nil otherButtonTitles:#"Ok",nil];
[alr show];
}
Here is a string print out from my location:
Entered new Location with the coordinates Latitude: 51.509980 Longitude: -0.133700
and here is a string print out from the region:
Entered new Location in Region (identifier London) <+51.50998000,-0.13370000> radius 30.00m

As #verbumdei commented, the only way you will get the -didEnterRegion and -didExitRegion is to establish a CLLocationManagerDelegate. Set your view as the delegate and add those methods and you should see the update.
One thing to note, you are using a 30M radius, you will need to be quite approximate in your location if you want to trigger updates. This is fairly easy to do in the Simulator, but in real life usage (on device), 30M accuracy is a bit tougher. I would start with 100M and work your way down based on experience.

If you start monitoring while staying in the target region, nothing triggered.
Because it's not really an "didEnterRegion" event.

You don't seem to be setting
region.notifyOnEntry = YES;
region.notifyOnExit = YES;
Without explicitly setting these properties, the specified events will not get fired.

Related

iOS: Can I detect the user located country?

Can I detect whether a user moved to another country?
(Not using Locale.current)
The location detection should be running in background.
I'm hoping to do something like this.
Eg. A user from US leaves the country to UK. Then, when the user reach UK, i am able to detect it at the background and send notification.
You should in your Info.plist, set allowsBackgroundLocationUpdates to YES, this you can search google, and lots of answer for adapt iOS 9.
First you can use CLLocationManager to get the location:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib .
//delegate
self.locationManager.delegate = self;
//The desired location accuracy.
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
//Specifies the minimum update distance in meters.
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.purpose = #"To provide functionality based on user's current location.";
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
UIAlertView* av = [[UIAlertView alloc] initWithTitle:#"update" message:[NSString stringWithFormat:#"didUpdateToLocation: newLocation: %# old:%#",newLocation,oldLocation] delegate:nil cancelButtonTitle:#"cancel" otherButtonTitles:#"ok", nil nil];
[av show];
}
Secondly, you can use CLGeocoder to get country or city.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
// get city name
CLGeocoder *geocoder = [[CLGeocoder alloc] init];
[geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *array, NSError *error)
{
if (array.count > 0)
{
CLPlacemark *placemark = [array objectAtIndex:0];
NSString *city = placemark.locality;
}
else if (error == nil && [array count] == 0)
{
NSLog(#"No results were returned.");
}
else if (error != nil)
{
NSLog(#"An error occurred = %#", error);
}
}];
}
You can give a duration to get location per duration:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{
newLocation = [locations lastObject];
double lat = newLocation.coordinate.latitude;
double lon = newLocation.coordinate.longitude;
NSLog(#"lat:%f,lon:%f",lat,lon);
if (!self.deferringUpdates) {
CLLocationDistance distance = 500;
NSTimeInterval time = 20;
[locationManager allowDeferredLocationUpdatesUntilTraveled:distance
timeout:time];
self.deferringUpdates = YES;
}
}
You can create UNNotificationRequest with exit UNLocationNotificationTrigger.
UNNotificationRequest
A UNNotificationRequest object is used to schedule a local notification and manages the content for a delivered notification. A notification request object contains a UNNotificationContent object with the contents of the notification. It also contains the UNNotificationTrigger object that specifies the conditions that trigger the delivery of the notification. For a delivered notification, you use these objects to fetch information about the notification.
UNLocationNotificationTrigger
A UNLocationNotificationTrigger object causes the delivery of a notification when the device enters or leaves a specified geographic region. Use this object to specify the region information needed to trigger the notification. Location triggers can fire once or they can fire multiple times.
Apps must request access to location services and must have when-in-use permissions to use this class. To request permission to use location services, call the requestWhenInUseAuthorization() method of CLLocationManager before scheduling any location-based triggers.
Flow
Each time user opens app, check his local country and define location trigger
let region: CLRegion = <your code defining country region>
region.notifyOnEntry = false
region.notifyOnExit = true
let trigger = UNLocationNotificationTrigger(region: region, repeats: false)
and using that trigger reschedule notification request (UNNotificationRequest).
When trigger fires (user leaves region) — app will present local notification, and if user taps on it, app starts, and if you add handler on local notification open you can notify your server about user moving away and check his new country and do what you need to do.

Cllocationmanager Didupdatelocation delegate not getting called without internet

I am currently working on a location based ios application. I am using didupdatelocation delegate method for showing user's current location. It works fine when I connect my device to internet. But when I disconnect the internet, it behaves strange and didupdatelocation is not getting called further. Please give a solution.
EDITED with code details
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc]init]; // initializing locationManager
locationManager.delegate = self; // we set the delegate of locationManager to self.
locationManager.desiredAccuracy = kCLLocationAccuracyBest; // setting the accuracy
[locationManager startUpdatingLocation]; //requesting location updates
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:#"Error" message:#"There was an error retrieving your location" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[errorAlert show];
NSLog(#"Error: %#",error.description);
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *crnLoc = [locations lastObject];
latitude.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.latitude];
longitude.text = [NSString stringWithFormat:#"%.8f",crnLoc.coordinate.longitude];
altitude.text = [NSString stringWithFormat:#"%.0f m",crnLoc.altitude];
speed.text = [NSString stringWithFormat:#"%.1f m/s", crnLoc.speed];
}
#ANSHAD per your comment, if you are using an older iPad without GPS, the only way you can get location data is with WiFi so if you turn off WiFi, you will not get location updates. If you want GPS without WiFi you can buy an external GPS module see here
You can use the base GPS of the iPhone which works without the internet too. To access it you need to use the CoreLocation framework.
You can refer to this : CoreLocation methods to use the GPS data.
Let me know if any other help required.

Calculating Distance between two coordinates using CLLocation

I'm using CLLocationDistance to get the distance between two points, but I'm getting an error when passing my current location in it.
CLLocation *current = [[CLLocation alloc] initWithLatitude:startLocation.coordinate.latitude longitude:startLocation.coordinate.longitude];
CLLocation *itemLoc = [[CLLocation alloc] initWithLatitude:[[[getName objectAtIndex:indexPath.row] objectForKey:#"lat"] doubleValue] longitude:[[[getName objectAtIndex:indexPath.row] objectForKey:#"lon"] doubleValue]];
//Here the current location gives me an error "Initializing cllocation with an expression incompatible format"
CLLocationDistance *itemDist = [itemLoc distanceFromLocation:current];
NSLog(#"Distance: %#", itemDist);
The error you're getting is actually:
Initializing 'CLLocationDistance *' (aka 'double *') with an expression of incompatible type 'CLLocationDistance' (aka 'double')
What it's saying is you're initializing itemDist (which you've declared as a CLLocationDistance *) to something that is returning a CLLocationDistance (notice no asterisk).
CLLocationDistance is not an object.
It is just a primitive type (specifically double -- see the Core Location Data Types Reference).
So instead of declaring itemDist as a pointer to a CLLocationDistance, just declare it as a CLLocationDistance (no asterisk):
CLLocationDistance itemDist = [itemLoc distanceFromLocation:current];
You'll also need to update the NSLog to expect a double instead of an object otherwise it will crash at run-time:
NSLog(#"Distance: %f", itemDist);
Is swift 2.0 is in the following way:
let userLocation:CLLocation = CLLocation(latitude: 11.11, longitude: 22.22)
let priceLocation:CLLocation = CLLocation(latitude: 33.33, longitude: 44.44)
let meters:CLLocationDistance = userLocation.distanceFromLocation(priceLocation)
Below code will work for you
in view load
//************************** GEtting USer's latitude/ Longitude ********************
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
//************************** GEtting USer's latitude/ Longitude ********************
pragma mark - CLLocationManagerDelegate
- (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;
if (currentLocation != nil) {
CLLocation *locA = [[CLLocation alloc] initWithLatitude:currentLocation.coordinate.longitude longitude:currentLocation.coordinate.latitude];
CLLocation *locB = [[CLLocation alloc] initWithLatitude:11.111111111111111 longitude:11.1111111111111111];
User_Vanue_Distance = [locA distanceFromLocation:locB];
NSLog(#"THIS IS THE DISTANCE BT TWO POINTS +++++++++++++++++++++%f",User_Vanue_Distance);
}
}
You need to put below keys in info.plist, in ios 8 to access location we need to put below keys in info.plist
1. NSLocationWhenInUseUsageDescription : Location required
2. NSLocationAlwaysUsageDescription Needed : Location Needed
This will work for you but one thing you need to add is add a check for ios8. otherwise this will crash on ios 7
// 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];
}
Hope this will work for you. :)
To find distance in KM from two different Lat & Long
let userLocation:CLLocation = CLLocation(latitude: 23.0320, longitude: 72.5250)
let priceLocation:CLLocation = CLLocation(latitude: 23.0283, longitude: 72.5067)
let distance = String(format: "%.2f km", userLocation.distanceFromLocation(priceLocation)/1000)
print("Distance is KM is:: \(distance)")

Get current location without a map view [duplicate]

I want to get the user's current location from my iPhone app. I want to show the user's current location like country name, latitude, longitude information in my app. And also i want to show the location in Google map also. I have tried Google search also, but can't get the exact answer. I have get the info that was to use CLLocationManager in my app to track the location. How do i use this? I have download one sample app from Apple Documents. Here is the link: https://developer.apple.com/library/ios/#samplecode/LocateMe/Introduction/Intro.html
Can you please help me on this? Thanks in advance.
1) I have get the info that was to use CLLocationManager in my app to track the location. How do i use this?
in .h file
#include <CoreLocation/CLLocationManagerDelegate.h>
#include <CoreLocation/CLError.h>
#include <CoreLocation/CLLocation.h>
#include <CoreLocation/CLLocationManager.h>
CLLocationManager * myLocationManager;
CLLocation * myLocation;
in .m file :-
-(void)findMyCurrentLocation
{
self.myLocationManager = [[[CLLocationManager alloc] init] autorelease];
[[self myLocationManager] setDelegate:self ];
[myLocationManager startUpdatingLocation];
double latitude=34.052234;
double longitude=-118.243685;
CLLocation *defaultLocation =[[CLLocation alloc] initWithLatitude:latitude longitude:longitude];
[self setMyLocation:defaultLocation];
[defaultLocation release];
if( [CLLocationManager locationServicesEnabled] )
{
NSLog(#"Location Services Enabled....");
locationServicesEnabled=TRUE;
UIAlertView *alert = [ [UIAlertView alloc] initWithTitle:#"Information"
message:#"Fetching your current location."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil ];
[alert release];
}
else
{
NSLog( #"Location Services Are Not Enabled...." );
locationServicesEnabled=FALSE;
UIAlertView *alert = [ [UIAlertView alloc] initWithTitle:#"Information"
message:#"Location service is not enable. Please enable it from settings."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil ];
[alert release];
}
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation: (CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
[self setMyLocation:newLocation];
NSString *tempLat = [ NSString stringWithFormat:#"%3.6f" , (newLocation.coordinate.latitude) ];
NSString *tempLong= [ NSString stringWithFormat:#"%3.6f" , (newLocation.coordinate.longitude)];
appDelegate.curlat = tempLat;
appDelegate.curlong = tempLong;
}
- (void)locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error
{
printf("\nerror");
UIAlertView *alert = [ [UIAlertView alloc] initWithTitle:#"Error"
message:#"Error while getting your current location."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil ];
[alert release];
}
2). I want to show the user's current location like country name information in my app.
For this you can to use Google's Reverse Geo coding OR MKReverseGeocoder
this should do most of it..
http://www.highoncoding.com/Articles/804_Introduction_to_MapKit_Framework_for_iPhone_Development.aspx
to get the information on the location you need to use MKReverseGeocoder
https://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKReverseGeocoder_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40008323
First create an instance of the MKMapView
To get user's latitude and longitude:
In your viewDidLoad
[yourMapView setShowsUserLocation:YES];
CLLocationCoordinate2D userCoord;
userCoord.latitude=map_view.userLocation.coordinate.latitude;
userCoord.longitude=map_view.userLocation.coordinate.longitude;
//NSLogging these on simulator will give you Cupertino or whatever location you set in location simulation.
And for country name you will need reversegeocoding you can look at the class reference here
https://developer.apple.com/library/ios/#documentation/MapKit/Reference/MKReverseGeocoder_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40008323
OR
If MKReverseGeoCoding gets too complicated you can use Yahoo's reversegeocoder
http://where.yahooapis.com/geocode?q=%f,%f&gflags=R&appid=yourAppId, those 2 %f will be userCoord.longitude and userCoord.latitude.
Yes you can use CLGeoCoder. But CLGeaCoder will not provide accrurate location inforamtion outside of USA for other country like India etc. So better to use Google's Reverse Geo coding SVGeoCoder. SVGeoCoder have nice implementation to get location with goolePlaceAPI.

didUpdateToLocation never called

I am using both the simulator and my device to test this, but no matter what I do, didUpdateToLocation is never called. I have tried changing my location in the sim, turning off and then on again my location services on my phone to force the phone to search for a new location... nothing. In my viewDidLoad(), I have started the CLLocationManager as so:
CLLocationManager *manager = [[CLLocationManager alloc] init];
if (![CLLocationManager locationServicesEnabled])
{
UIAlertView *servicesDisabledAlert = [[UIAlertView alloc] initWithTitle:#"Location Services Disabled" message:#"You currently have all location services for this device disabled. If you proceed, you will be asked to confirm whether location services should be reenabled." delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[servicesDisabledAlert show];
} else {
manager.desiredAccuracy = kCLLocationAccuracyBest;
manager.delegate = self;
[manager startUpdatingLocation];
}
and in the update location method I have this:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"NEW LOCATION! Accuracy:[%f]",newLocation.horizontalAccuracy);
}
Does anyone have any ideas why this isn't being called?
Did you add location delegate in your header file ?
I don't know if this is the issue but try
manager.desiredAccuracy = kCLLocationAccuracyKilometer;
or
manager.desiredAccuracy = kCLLocationAccuracyTenMeters;
instead of
manager.desiredAccuracy = kCLLocationAccuracyBest;
and see if that makes any change.
Setting desiredAccuracy to best timed out most of the times when I test my location dependent apps on my iPhone. Especially when you are indoors.

Resources