Stuck on CLLocation - iphone

This is more of a theoretical question than code:
What i did till now :
My app is heavily dependent upon location tracking.
I posted a question about it around 5 hours back without a suitable answer and it is now pretty old to put a new question there .i will closing it after i get an answer for this question.
What i want to do is to have a button that user presses.it makes location manager to start updating locations and then for every 5 feet moved . i want to make iPhone play random sounds.
i implemented correct code given below and now i tested on my device moving from one place to here in my house. through trial and errors i got to know that first few locations are iPhone trying to get an accurate results and are generally to be avoided so i made it a condition to process location which come after more than 2 seconds to previous.
Now my Real ques :
I have my device on wifi.(don't have gps and can't have) so after few initial useless location updates . my alerts stop showing.. i was like : why isn't working . i set it to accuracy best. did filtering to 1.5 meters .. i was moving like 15 feets in the house and no update ?..now i think it is because it is taking locations through wifi and hence it is founding no new locations even if i move 40 feeds around that wifi.? am i correct?
If that is true .. can anyone tell will this work correctly in gps .. for U.S. users..where they have lots of towers.. so that my app will correctly update that new location is at least 5 meters away from its previous location..
Sorry for the long question.. There are too many doubts for me..
-(id) init
{
if(self = [super init])
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
// locationManager.distanceFilter = 1.5;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
return self;
}
return nil;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"New Lcoation"
message:nil
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
self.currentLocation = newLocation;
BOOL newLocationIsValid = [self isValidLocation:newLocation withOldLocation:oldLocation];
if(newLocationIsValid && oldLocation)
{
int distance = [newLocation distanceFromLocation:oldLocation];
if(distance >2 && distance <10)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Distance"
message:[NSString stringWithFormat:#"%i meters",distance]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
[fileURl release];
}
}
}
-(BOOL)isValidLocation:(CLLocation*)newLocation withOldLocation:(CLLocation*)oldLocation
{
if(newLocation.horizontalAccuracy < 0 )
{
return NO;
}
NSTimeInterval secondsSinceLastPoint = [newLocation.timestamp timeIntervalSinceDate:oldLocation.timestamp];
if(secondsSinceLastPoint < 0)
{
return NO;
}
if(secondsSinceLastPoint < 2)
{
int distance = [newLocation distanceFromLocation:oldLocation];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Distance"
message:[NSString stringWithFormat:#"%i meters",distance]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
return NO;
}
return YES;
}

yes, doesn't work because you use wifi for locating. The Location-Service just know where your wifi is, not your position relative to your wifi (that would be nice).
so for your service you must use gps. and even then, the accuracy is not garanteed.
see http://www.kowoma.de/en/gps/accuracy.htm

When you are not using the real GPS signal the location is retrieved via triangulation, which is in no way near accuracy you want. Even if there are many WiFi or cell towers the accuracy is still a couple of meter, more like 100 then 10.
The accuracy you want can only be achieved with GPS, which is some cases will only have an accuracy of 100 meters or so. It all depends on the GPS signal quality.

Related

continously check for location services enabled in ios

I am trying to make an app in which the view will check whether the location services are enabled or not . If it is not enabled then it will prompt one with a pop up but still it will keep on searching for location but not prompt. As soon as the location services are enabled it will continue its process.
How to do that???
You cannot continue getting the location if location service are disabled.
If you want to continue searching for location be sure that the service is enable by checking
[CLLocationManager locationServicesEnabled]
If enabled, start updating the location
[locationManager startUpdatingLocation];
Then in
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
[locationManager stopUpdatingLocation]; // This will stop to check the location
}
remove this code to still check the location [locationManager stopUpdatingLocation];, but this is not the best approach, be sure to read the apple documentation for the policy of getting the location
You can check location services availability through this code :
MKUserLocation *userLocation = map.userLocation;
BOOL locationAllowed = [CLLocationManager locationServicesEnabled];
BOOL locationAvailable = userLocation.location!=nil;
if (locationAllowed==NO) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Location Service Disabled"
message:#"To re-enable, please go to Settings and turn on Location Service for this app."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
} else {
if (locationAvailable==NO)
[self.map.userLocation addObserver:self forKeyPath:#"location" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:nil];
}
Add in .h file int counter;
In your view's viewDidLoad method add this as it will check for every second u can increase counter:
[NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(checkLocationMangerEnabled:)
userInfo:nil
repeats:YES];
counter = 0;
Now selector would be:
-(void)checkLocationMangerEnabled:(id)sender
{
if([CLLocationManager locationServicesEnabled])
{
//here location is enabled
}
else
{ //Not enabled
if(counter == 60) // alert will showed in every 1 min u can increase or decrese
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Location Service Disabled"
message:#"To re-enable, please go to Settings and turn on Location Service for this app."
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
counter++;
}
}

iOS: get Accurate Reverse Geocoding using CLLocationManager?

Background: I want to allow users to get their location within seconds when they want it. However, the location is mostly inaccurate. I want to ask the user to if they would like to try again for a more accurate address.
Question: How to code such that it guarantees that the next guess, is always better than the last guess.
What I have tried:
CLLocationManager *locationManager;
- (CLLocationManager *)locationManager {
if (locationManager != nil) {
return locationManager;
}
locationManager = [[CLLocationManager alloc] init];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager setDelegate:self];
return locationManager;
}
-(void)myLocationClickedWithCount: (int) count{
[[self locationManager] startUpdatingLocation];
CLLocation *location = [locationManager location];
CLGeocoder *locationGeocoded = [[CLGeocoder alloc] init];
[locationGeocoded reverseGeocodeLocation:location completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
if (!placemark){
if (count > 0){
//placemark not available, try again after 1 second
sleep(1);
[self myLocationClickedWithCount:count-1];
}
else{
//Unable to get location after 3 tries
UIAlertView *locationNotFoundAlert = [[UIAlertView alloc]initWithTitle:#"Unable to Locate" message:#"Would you like to try again?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
locationNotFoundAlert.tag = locationNotFoundAlertTag;
[locationNotFoundAlert show];
}
}else{
// got location but not accurate.
if (location.horizontalAccuracy > accuracyRadius) {
UIAlertView *locationInaccurateAlert = [[UIAlertView alloc]initWithTitle:#"Inaccurate Location" message:[NSString stringWithFormat:#"Your GPS shows the radius of %.2f meters. Would you like to try again?",location.horizontalAccuracy] delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
locationInaccurateAlert.tag = locationInaccurateAlertTag;
[locationInaccurateAlert show];
}else {
address.text = placemark;
}
}
}];
}
Update
When the user asks again, it can take a little longer to guess. I just want to know how I should code it. IE: Should I call [[self locationManager] startUpdatingLocation]; again? or will that reset my location so far. Hence, how can i improve my guess the second time based on the current information GPS has (the longer GPS is on, the better accuracy right?).
there is nothing much you can do regarding accuracy via code... apart from
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
which you have already done...
As far as I have seen if you are on 3G or EDGE than your accuracy increases considerably (accuracy level of 5-10m can be achieved).
you can refer this article by Apple which talks how the iphone GPS accuracy works...
hoping this helps..

Can anyone help me out with using CLLocationManager?

I have two questions. (First) I'm trying to make it where whenever the iPhone moves in location at all, an alert box pops up and shows the longitude where they were, and the latitude where they are now. This is for testing purposes for part of a bigger project I'm working on. Problem is, no alert box is popping up at all. I thought that when the location manager gets a new location, it fires up the delegate which should show the location in an alert box, however nothing is happening at all.
Here is how I'm setting up the Location Manager:
- (void)viewDidLoad
{
locationManager =[[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLDistanceFilterNone;
[locationManager startUpdatingLocation];
}
Here is the delegate:
-(void) locationmanager: (CLLocationManager *) manager
didUpdateToLocation: (CLLocation *) newLocation
fromLocation: (CLLocation *) oldLocation
{
float oldlat;
float oldlng;
float lat;
float lng;
NSDate *oldtime;
NSDate *newtime;
lat = newLocation.coordinate.latitude;
lng = newLocation.coordinate.longitude;
newtime = newLocation.timestamp;
oldlat = oldLocation.coordinate.latitude;
oldlng = oldLocation.coordinate.longitude;
oldtime = oldLocation.timestamp;
NSNumber *oldlong = [NSNumber numberWithFloat:oldlng];
NSNumber *newlat = [NSNumber numberWithFloat:lat];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:oldlong
message:newlat
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Submit",nil];
[alert show];
(Secondly) once I'm satisfied that I'm able to track the new and old latlng, does anybody know the best way to store the data? I have researched sqlite, core data, and just using arrays, but i'm still having doubts as to whats the best way to store the lat, lng, timestamp and username that will be generated probably a couple hundred times a day for around 200 users, and then send it to a server.
I know this was a long question, but any insight at all would be greatly appreciated!
Ok. I am really astonished why your application did not crash at this line:
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:oldlong
message:newlat
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Submit",nil];
If try to understand UIAlertView parameters properly you will see initWithTitle and message parameters are of type NSString and what you are passing is NSNumber so take two
NSString for lattitude and longitude and pass them as a parameter like this.
NSString *long1=[[NSString alloc]initWithFormat:#"%f",oldlong];
NSString *lat1=[[NSString alloc]initWithFormat:#"%f",newlat];
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:long1
message:lat1
delegate:self
cancelButtonTitle:#"Cancel"
otherButtonTitles:#"Submit",nil];
But showing alert in didUpdateToLocation won't be a good idea as it will constantly gets called so you will have alert pop up each second locking up your interaction. Though this code worked for me. Have a look at screenshot.

How to get the user's current location by code in iphone app?

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.

UIAlertView Pops Up Three Times per Call Instead of Just Once

I am getting odd behavior from an NSAlert in two different parts of my program. The behavior is:
Alert appears and then spontaneously disappears.
Alert reappears and then remains until dismissed by user i.e. normal behavior.
Alert reappears again.
This behavior only occurs the first time the method that displays the alert is called. After that first time, it behaves normally.
Here is the code for the one of the parts in which the behavior occurs:
UIAlertView * locationAlert = [[UIAlertView alloc] initWithTitle:#"You are in the right place." message:nil delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[locationAlert show];
[locationAlert release];
Or if you prefer, with a bit more context:
- (IBAction)locateMe {
NSLog(#"About to check location");
locMan = [[CLLocationManager alloc] init];
locMan.delegate = self;
locMan.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
locMan.distanceFilter = 1609; //1 mile
[locMan startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation * )oldLocation {
if (newLocation.horizontalAccuracy >= 0) {
CLLocation *airportLocation = [[[CLLocation alloc] initWithLatitude:51.500148 longitude:-0.204669] autorelease];
CLLocationDistance delta = [airportLocation getDistanceFrom: newLocation];
long miles = (delta * 0.000621371) + 0.5; //metres to rounded mile
if (miles < 3) {
UIAlertView * locationAlert = [[UIAlertView alloc] initWithTitle:#"You are in the right place." message:nil delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[locationAlert show];
[locationAlert release];
[locMan stopUpdatingLocation];
} else {
UIAlertView * locationAlert = [[UIAlertView alloc] initWithTitle:#"You are not in the right place." message:nil delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[locationAlert show];
[locationAlert release];
[locMan stopUpdatingLocation];
}
}
}
- (void) locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
UIAlertView * locationAlert = [[UIAlertView alloc] initWithTitle:#"Error." message:error.code delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[locationAlert show];
[locMan release];
locMan = nil;
}
Any ideas? Thanks.
Edit---------
The other place this happens is:
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError {
NSString * errorString = [NSString stringWithFormat:#"Unable to download feed from web site (Error code %i )", [parseError code]];
NSLog(#"error parsing XML: %#", errorString);
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Error loading content" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
}
For context the first case is in the AppDelegate and the second in the view controller for the 1st tab view. The second problem occurs every time the xml is reloaded when there is no internet connection. The first one only occurs the first time the function is called.
Edit-----
If I move the alert it works. Unfortunatly this is not where I want it!
- (IBAction)locateMe {
UIAlertView * locationAlert = [[UIAlertView alloc] initWithTitle:#"You are in the right place." message:nil delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[locationAlert show];
/*
NSLog(#"About to check location");
locMan = [[CLLocationManager alloc] init];
locMan.delegate = self;
locMan.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
locMan.distanceFilter = 1609; //1 mile
[locMan startUpdatingLocation];*/
}
Update:
I set some NSLog entries and discovered that despite the addition of [locMan stopUpdatingLocation] the didUpdateToLocation function was running multiple times.
I guess the spontaneous disappearance happens because the alert view is called again and the programme clears the first instance to make way for the second automatically.
Any ideas as to why [locMan stopUpdatingLocation] doesn't work would be appreciated but in the mean time I just moved the declaration of the locationAlert out of the function (so it is global), set it in the initial locate me function and use the following the first time it is called:
[locationAlert show];
locationAlert = nil;
That way it works perfectly.
You're not turning off your location manager when you first show the alert. As the location is refined by the device (ie, the accuracy is increased), your callback will be (potentially) called multiple times. You should use [locMan stopUpdatingLocation] after your alert display.
I set some NSLog entries and discovered that despite the addition of [locMan stopUpdatingLocation] the didUpdateToLocation function was running multiple times.
I guess the spontaneous disappearance happens because the alert view is called again and the programme clears the first instance to make way for the second automatically.
Any ideas as to why [locMan stopUpdatingLocation] doesn't work would be appreciated but in the mean time I just moved the declaration of the locationAlert out of the function (so it is global), set it in the initial locate me function and use the following the first time it is called:
[locationAlert show];
locationAlert = nil;
That way it works perfectly.
I think the NSAlert disappearing on its own is the key to solving this.
It's simple to explain why an alert displays unexpectedly i.e. it's just been called unexpectedly. However, it's not so common to programmatically dismiss an alert. Whatever is causing it to disappear is most likely triggering the display again.
To debug I suggest:
(1) Looking in your code for the NSAlert – dismissWithClickedButtonIndex:animated: method and see if somehow you're actually dismissing the alert programmatically.
(2) I believe (someone double-check me on this) that an alert view is added as a subview to whichever base view is currently on screen. It might be that the base view is disappearing for some reason and taking the alert view with it. If the view disappears and then reappears rapidly enough, it might not be obvious when the alert is frontmost. (Edit: see Ed Marty's comment below.)
(3) Since this happens in two separate pieces of the app, compare both to find a common element or structure. That common element might be the cause.
An odd problem.
Edit01: Updated for additional info
If locMan isan instance variable, it should be defined as a property and you should access it every time withself.locMan By accessing it directly, you lose your automatic retention management.
I encountered the same exact issue with the alert dialog appearing momentarily, reappearing, and finally appearing again after being dismissed. I was making a string comparison before deciding to show the alert view:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if([string isEqualToString:#"OK"]) {
NSLog(#"(Settings)Registration Successful");
statusField.text = #"Registration successful!";
[settingsActivity stopAnimating];
}
else {
NSLog(#"(Settings)Registration Failure");
[settingsActivity stopAnimating];
UIAlertView * regFail = [[[UIAlertView alloc] initWithTitle:#"Registration Error!" message:#"Please check your email address and try again." delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil] autorelease];
[regFail show];
}}
To correct this behavior I simply verified the returned string rather than just showing the alert:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if([string isEqualToString:#"OK"]) {
NSLog(#"(Settings)Registration Successful");
statusField.text = #"Registration successful!";
[settingsActivity stopAnimating];
}
else if([string isEqualToString:#"Error"]) {
NSLog(#"(Settings)Registration Failure");
[settingsActivity stopAnimating];
UIAlertView * regFail = [[[UIAlertView alloc] initWithTitle:#"Registration Error!" message:#"Please check your email address and try again." delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil] autorelease];
[regFail show];
}
I also got the Same problem while working on Location Manager. Here i checked with Nslog but it is executing multiple times, finally i fount that i am creating multiple objects and using Sharedinstance for same ViewController that contains Location Manger but i am not releasing the object, so at perticular location how many objects if we create that many times the location detects.So while working on LocationManger check handling objects thoroughly to reduce these type of problems.