How to make forced update of user location? - iphone

I need to get current user location but I don't know if it has changed or not. Can I request a forced location update from CLLocationManager? Or is there any other way to do that?

Stopping and restarting the LocationManager should force the device to re-acquire an initial position.
[locationManager stopUpdatingLocation];
[locationmanager startUpdatingLocation];

I have had the same problem in one of my apps. I actually had to change the app structure.
This is what I have done:
This class has a public method. -(void)locateMe; an abstract class needs to instantiate this class and run the locateMe then when userIsLocated a notification will be broadcasted. and another method can get the result coordinates from (CLLocation *)currentLocation;
#import <Foundation/Foundation.h>
#import <MapKit/MapKit.h>
#interface ManageUserLocation : NSOperation <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *currentLocation;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) CLLocation *currentLocation;
-(void) locateMe;
#end
in the .m
#import "ManageUserLocation.h"
#implementation ManageUserLocation
#synthesize locationManager;
#synthesize currentLocation; // Other classes use this to get the coordination even better you can make another method that even dont get the direct access to currentLocation. It is up to you.
- (id)init
{
self = [super init];
if (self) {
//[self locateMe]; // Just a hook if you need to run it
}
return self;
}
-(void) locateMe {
self.locationManager = nil;
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy=kCLLocationAccuracyBest;
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// User location has been found/updated, load map data now.
[self.locationManager stopUpdatingLocation];
currentLocation = [newLocation copy];
// WooHoo Tell everyone that you found the userLocation
[[NSNotificationCenter defaultCenter] postNotificationName:#"userLocationIsFound" object:nil];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
// Failed to find the user's location. This error occurs when the user declines the location request or has location servives turned off.
NSString * errorString = #"Unable to determine your current location.";
UIAlertView * errorAlert = [[UIAlertView alloc] initWithTitle:#"Error Locating" message:errorString delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
[locationManager stopUpdatingLocation];
}
- (void)dealloc { #warning dont forget this :) }
#end
Hope this help.

I think is contrary to Apple Guidelines to force updates.
Apple says geo-update will occur automatically, but at un unknown time.

Related

How to get current Location info using wifi or cellular without using GPS in ios

Currently I am working in a project , its requirement is to get the current location information specially latitude and longitude value in every 200m interval using wifi network or Cellular network without using gps as it is consuming more battery life.
Is this possible in ios latest version .
If any one having any idea ,please share with me ,
Thank you.
Have a look in to CLLocationManager, That will be able to tell you where the user is located.
.h
#import <CoreLocation/CoreLocation.h>
#property(nonatomic,retain) CLLocationManager *locationManager;
.m
- (void)viewDidLoad
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//let the user know the purpose
locationManager.purpose = #"Enable location services";
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
NSLog(#"User latitude: %f",locationManager.location.coordinate.latitude);
NSLog(#"User longitude: %f",locationManager.location.coordinate.longitude);
[locationManager startUpdatingLocation];
}
It only way to get your location info in every 200m that is CLLocationManager's startUpdatingLocation. But it is comsuming a lot of battery.
But there is a little different way to get your location when it is changed.
CLLocationManager's startMonitoringSignificantLocationChanges.
Here is a Link
The location manager protocol reference
https://developer.apple.com/library/mac/#documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/CLLocationManagerDelegate/CLLocationManagerDelegate.html
1.In Appdelegate
#import <CoreLocation/CoreLocation.h>
In #interface file
CLLocationManager *locationManager;
#property (nonatomic, retain) CLLocationManager *locationManager;
and add protocol CLLocationManagerDelegate protocol.
2.Impliment these functions in .m.
#synthesize locationManager;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = 1.0;
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
// Show an alert or otherwise notify the user
}
- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
}
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error
{
}
Note:If you want to debug first set current location in simulator
At Debug--->Location--->Custom Location.
its requirement is to get the current location information specially latitude and longitude value in every 200m interval using wifi network or Cellular network without using gps as it is consuming more battery life
The documentation for CLLocationManager has this to say about distance and the GPS hardware:
... setting the desired accuracy for location events to one kilometer gives the location manager the flexibility to turn off GPS hardware and rely solely on the WiFi or cell radios.
For less than 200 meters you'll probably need to roll-your-own solution here.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[locationManager stopUpdatingLocation];
[locationManager stopMonitoringSignificantLocationChanges];
[self performSelector:#selector(stopUpadateLocation)];
CLLocation *location = [locationManager location];
CLLocationCoordinate2D coord;
coord=[location coordinate];
NSLog(#"coord %f %f", coord.latitude, coord.longitude);
NSString *urlString = [NSString stringWithFormat:#"http://maps.google.com/maps/geo?q=%f,%f&output=json", newLocation.coordinate.latitude, newLocation.coordinate.longitude];
NSURL *url = [NSURL URLWithString:urlString];
NSString *locationString = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:nil];
NSDictionary *dic=[locationString JSONValue];
NSLog(#"locationString:%#",locationString );
[strAddr setString:[AppUtility removeNull:[NSString stringWithFormat:#"%#",[[[dic valueForKey:#"Placemark"] objectAtIndex:0] valueForKey:#"address"]]]];
[txtNear setText:strAddr];
}
- (void)startUpdateLocation{
[locationManager startUpdatingLocation];
}
- (void)stopUpadateLocation{
[locationManager stopUpdatingLocation];
[locationManager stopMonitoringSignificantLocationChanges];
}
You have to use the Core Location method startMonitoringSignificantLocationChanges which uses only the wifi or cellular networks!

Why isn't locationManager:didUpdateLocations being called?

Here is some simple code:
// ViewControllerA.m
-(void) viewDidLoad
{
[super viewDidLoad];
self.networkMonitor = [[NetworkMonitor alloc] init];
...
[self.networkMonitor.locationManager startUpdatingLocation];
...
}
in network monitor:
// NetworkMonitor.m
-(id) init
{
self = [super init];
if (self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
[self.locationManager setDelegate:self];
}
return self;
}
...
// this is never called!
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"%s, location manager returned a new location.", __FUNCTION__);
...
}
// and neither is this
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Error: %#", [error description]);
}
I've called startUpdatingLocation, NetworkMonitor implements CLLocationManagerDelegate...why am I not getting any calls to didUpdateLocations? Am I misunderstanding when this method should get called? I assume that once startUpdatingLocation is called, I should receive at least one call to didUpdateLocations... I'm simply trying to get the user's current location (without using a map). Any ideas or thoughts would be much appreciated.
are you building for ios6? from docs: In iOS 5 and earlier, the location manager calls the locationManager:didUpdateToLocation:fromLocation: method instead.

How can I match the place with the result of CLGeocoder?

I can get the result (like locality, ISOcountryCode, etc) by CLGeocoder's reverseGeocodeLocation:completionHandler: method successfully.
But how can I match the place with the result?
e.g.: If the city (locality) of result is Hangzhou City, I can match it simply by using
if ([placemark.locality isEqualToString:#"Hangzhou City"]) {...}
But as you know, there're millions of cities, it's impossible to get the city name one by one and hard code into my app.
So, is there any way to solve this problem? Or does there any framework exist? Or just several files contain countries & cities' name that match the CLGeocoder's result? Even fuzzy coordinate matching solution is okay (I mean, a city has its own region, and I can determine the city just by coordinate, but I still need to get every city's region area at the moment).
Deployment Target iOS5.0
Well there is a easier way, you can use the reverse GeocodeLocation to get the information of the place. You have to know this won't work in every city thought.
For more information check Apple's CLGeocoder Class Reference and Geocoding Location Data documentation.
So you can create and object that handle the service
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#interface locationUtility : NSObject<CLLocationManagerDelegate>{
CLLocationManager *locationManager;
CLPlacemark *myPlacemark;
CLGeocoder * geoCoder;
}
#property (nonatomic,retain) CLLocationManager *locationManager;
#end
and the implementation
#import "locationUtility.h"
#implementation locationUtility
#synthesize locationManager;
#pragma mark - Init
-(id)init {
NSLog(#"locationUtility - init");
self=[super init];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLDistanceFilterNone;
[locationManager startMonitoringSignificantLocationChanges];
geoCoder= [[CLGeocoder alloc] init];
return self;
}
- (void) locationManager:(CLLocationManager *) manager didUpdateToLocation:(CLLocation *) newLocation
fromLocation:(CLLocation *) oldLocation {
[geoCoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
CLPlacemark *placemark = [placemarks objectAtIndex:0];
myPlacemark=placemark;
// Here you get the information you need
// placemark.country;
// placemark.administrativeArea;
// placemark.subAdministrativeArea;
// placemark.postalCode];
}];
}
-(void) locationManager:(CLLocationManager *) manager didFailWithError:(NSError *) error {
NSLog(#"locationManager didFailWithError: %#", error.description);
}
#end

didUpdateLocation Method Never Called

I am making one app on iphone sdk4.0.In that did update location method never called.
I have given my code below.Please help.Thanks in advance.
-(id)init
{
[super init];
obj=[[UIApplication sharedApplication]delegate];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
//locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
return self;
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"%f",newLocation.coordinate.latitude);
NSLog(#"%f",newLocation.coordinate.longitude);
obj=[[UIApplication sharedApplication]delegate];
location=[[CLLocation alloc]initWithLatitude:newLocation.coordinate.latitude longitude:newLocation.coordinate.longitude];
obj.lattitude1=[NSString stringWithFormat:#"%f",newLocation.coordinate.latitude];
obj.longitude1=[NSString stringWithFormat:#"%f",newLocation.coordinate.longitude];
//location=[[CLLocation alloc]initWithLatitude:39.9883 longitude:-75.262227];
}
Furthermore in iOS8 you must have two extra things:
Add a key to your Info.plist and request authorization from the location manager asking it to start.
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
You need to request authorization for the corresponding location method.
[self.locationManager requestWhenInUseAuthorization]
[self.locationManager requestAlwaysAuthorization]
Code example:
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// 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];
}
[self.locationManager startUpdatingLocation];
Source: http://nevan.net/2014/09/core-location-manager-changes-in-ios-8/
HI, your codes seems ok.
now these can be possible reasons :
on your init: try to check if there is locationServicesEnabled or not.
locationManager = [[CLLocationManager alloc] init];
if(locationManager.locationServicesEnabled == NO){
//Your location service is not enabled, Settings>Location Services
}
other reason, you may disallow to get location to your app.
solution: simply remove your application from iPhone and re-build, now it should popup dialog to Allow location.
use this to check error
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Error while getting core location : %#",[error localizedFailureReason]);
if ([error code] == kCLErrorDenied) {
//you had denied
}
[manager stopUpdatingLocation];
}
otherwise all seems ok,
you were already running ios 4.0 , which can be install in iPhone 3G and later,
if it was iPhone 2g, then this problem may occur.
Make sure you added CLLocationManager as a property.
#property (nonatomic , strong) CLLocationManager *locationManager;
If you are testing this on the simulator it will not work.
This happens because that method is only called when the device changes location (and the simulator never changes location).
Does -locationManager:didFailWithError: in your delegate ever get called? Maybe you denied access to location data at some point and now don't get prompted, but access is denied.
After you alloc and init your location manager, check to see if location services are allowed. This code is from Apple's "LocateMe" code sample
if (locationManager.locationServicesEnabled == NO) {
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];
[servicesDisabledAlert release];
}
If you're testing with the simulator, try testing with a device instead. The simulator requires that the computer's WiFi is turned on, and that it can locate a WiFi base station that's in it's database of known locations.

IPhone - MKReverseGeocoder - how to make sure I have the result back

what i'm trying to reach is to display annotation with the city name.
So I have a class MapPoint :
#interface MapPoint : NSObject<MKAnnotation,MKReverseGeocoderDelegate> {
NSString* title;
NSString* cityName;
CLLocationCoordinate2D coordinate;
MKReverseGeocoder* reverseGeo;
}
#property (nonatomic,readonly) CLLocationCoordinate2D coordinate;
#property (nonatomic,copy) NSString* title;
#property (nonatomic,copy) NSString* cityName;
-(id) initWithCoordinate:(CLLocationCoordinate2D)c tilte:(NSString*)t;
#end
I implemented it like this :
#implementation MapPoint
#synthesize title,coordinate,cityName;
-(id) initWithCoordinate:(CLLocationCoordinate2D)c tilte:(NSString*)t
{
[super init];
coordinate = c;
reverseGeo = [[MKReverseGeocoder alloc] initWithCoordinate:c];
reverseGeo.delegate = self;
[reverseGeo start];
[self setTitle:t];
return self;
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
NSString* city = [placemark.addressDictionary objectForKey:(NSString*)kABPersonAddressCityKey];
NSString* newString = [NSString stringWithFormat:#"city-> %#",city];
[self setTitle:[title stringByAppendingString:newString]];
}
-(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error{
NSLog(#"error fetching the placemark");
}
-(void)dealloc
{
[reverseGeo release];
[cityName release];
[title release];
[super dealloc];
}
#end
Then, in my CoreLocation delegate I use MapPoint like that:
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
MapPoint* mp = [[MapPoint alloc] initWithCoordinate:[newLocation coordinate] tilte:[locationTitleField text]];
[mapView addAnnotation:mp];
[mp release];
}
Now, I have 2 issues I'm not sure of :
Is it correct to put reverseGeo as a data member , or a better option would be to just
alloc it inside the initializer and release it inside the didFindPlacemark/didFailWithError delegates(is it even possible to release it there) ?
How can I make sure then when my annotation get displayed I know for sure that the reverseGeo came back with an answer (placemark or error - whatever it is).
Maybe it's just wrong to wait for network response and I should leave it like that - I'm just not sure then when/if network response will arrive it will update the annotationView within the MapView accordingly.
Please elaborate as much as you can.
Thanks
It's fine to store it as a data member.
It looks like you're leaving a trail of annotations for the user's current location? If you're supplementing a regular user's-current-location annotation with a "bread crumb trail" showing where the user has been, then you need to wait to add the point to the map until you get the annotation back (if that's the behavior you want). I would either do that by making the class that manages your map be the MKReverseGeocoder delegate (and have it set the title property and then add the annotation to the map in reverseGeocoder:didFindPlacemark) or add a map reference to your MapPoint class and have it add itself to the map in the same callback.
By the way, the documentation for MKReverseGeocoder includes the following text:
When you want to update the location automatically (such as when the user is moving), reissue the reverse-geocoding request only when the user's location has moved a significant distance and after a reasonable amount of time has passed. For example, in a typical situation, you should not send more than one reverse-geocode request per minute.