i have been trying to implement the following code on my device:-
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface Whereami1ViewController : UIViewController<CLLocationManagerDelegate>
{
CLLocationManager *locationManager;
__weak IBOutlet UILabel *coordLabel;
}
#end
#implementation Whereami1ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
locationManager.distanceFilter= 5.00;//5 meters
[locationManager startUpdatingLocation];
}
return self;
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations{//location manager sends this message to self
NSLog(#"%#",NSStringFromSelector(_cmd));
NSLog(#"new location–– %#",[locations lastObject]);
NSLog(#"latitude= %f, longitude= %f",[[locations lastObject] coordinate].latitude, [[locations lastObject] coordinate].longitude);
CGSize coordData= {[[locations lastObject] coordinate].latitude, [[locations lastObject] coordinate].longitude};
coordLabel.text= NSStringFromCGSize(coordData);//setting the label's text
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{
NSLog(#"%#",NSStringFromSelector(_cmd));
NSLog(#"location not found: %#", error);
}
#end
In the code i have set the distance filter as 5 meters. This means after 5 meters worth of movement the device goes through, it should be updating the label's text to a new coordinate,(latitude, longitude). But this is not happening in reality. I mean
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
should get called only when the device has moved more than 5 meters.In actuality, the device is stuck with the initial data (the label does not update in the view)..
What am i doing wrong.. Isn't this the right way??
The iPod touch uses WiFi networks for location service. So it may be impossible to get a good location or an update for 5 meter moves?! It ill behave quite different than an iPhone or iPda that also use GPS signals for location.
Related
I'm trying to getting my current location exact according to my coordinates. I've implemented CLLocationManager in my viewController called myLocation.
My problem is, I'm getting not getting my co-ordinates for the first time, but when I again approach I got the coordinates. I'm unable to understand this problem that why this not appear for the first time.
I also tried to give a NSTimer to stoplocation but but still unable to get the result for the first time, every first time I getting a (null) value, and then getting the co-ordinates.
My Code:
#import <UIKit/UIKit.h>
#import <Corelocation/CoreLocation.h>
#interface myLocation : UITableViewController<CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#interface myLocation () {
CLLocationManager* _locationManager;
NSString * _lat;
NSString * _lng;
}
#end
#implementation myLocation
- (void)viewDidLoad
{
[super viewDidLoad];
_locationManager = [[CLLocationManager alloc] init];
_locationManager.distanceFilter = kCLDistanceFilterNone;
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
[_locationManager requestWhenInUseAuthorization];
[_locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {
CLLocation *location = [locations lastObject];
[_locationManager stopUpdatingLocation];
_lat =[NSString stringWithFormat:#"%f",location.coordinate.latitude];
_lng =[NSString stringWithFormat:#"%f",location.coordinate.longitude];
}
- (void)viewWillAppear:(BOOL) animated
{
NSLOG(#"%#",_lat);
NSLOG(#"%#",_lng);
}
Your coordinates aren't appearing yet when you attempt to print them in viewWillAppear: because the CLLocationManager hasn't had enough time to retrieve the first location yet. Wait until didUpdateLocations: is first called before attempting to utilize the device coordinates because didUpdateLocations: is where you'll be receiving those coordinates. I recommend deleting your attempt to print the coordinates code from your viewWillAppear and simply print them in didUpdateLocations: instead.
In the comments, the OP stated he wants to "refresh" the location during viewWillAppear. I suggest stopping the updates when the view disappears and restarting the updates as soon as the view reappears:
- (void)viewWillAppear:(BOOL) animated
{
[_locationManager startUpdatingLocation];
}
- (void)viewWillDisappear:(BOOL) animated
{
[_locationManager stopUpdatingLocation];
}
It takes some time for location services to start up and call your delegate method - This almost certainly won't happen before viewWillAppear is called if you are only starting location services in viewDidLoad. Also, the first time your app executes it has to wait for the user to grant permission.
You can examine the location property of your CLLocationManager to get the most recent location. If it is nil then no location has been determined (yet).
I'm trying to put everything location related inside a model. When I call this my MainViewController, the simulator doesn't ask me for my location, and nothing happens.
When I use the same code from my model, but put it directly in ViewDidLoad in my ViewController, everything works. I'm having a hard time understanding why.
Here is my model:
#implementation Location
{
CLLocationManager *_locationManager;
CLLocation *_location;
}
- (void)startLocationManager
{
NSLog(#"In startLocationManager");
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
_locationManager.delegate = self;
[_locationManager startUpdatingLocation];
}
#pragma mark - LocationManager Delegates
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(#"In didUpdateLocations");
if (locations) {
_location = [locations lastObject];
NSLog(#"%#", _location);
}
}
#end
I call this in my MainViewController like this:
- (void)viewDidLoad
{
[super viewDidLoad];
Location *location = [[Location alloc] init];
[location startLocationManager];
}
Why does the code work like a charm directly in the viewController, but not through my model?
I figured it out.
I needed to make location a property of your view controller instead of a local variable in the viewDidLoad. Otherwise it is created and deallocated within that method. I need it to live through the lifecycle of my view controller.
I'm trying to make an iOS7 app that uses the current location of the device. I'm using the iPhone simulator on my Mac, but I'm having some problems. Every time my view that the location manager is in appears, it prints out 0.000000 for both latitude and longitude, even after I've set a custom location (from simulator>debug>location).
Also, it seemed strange that the simulator didn't ask for permission to use current location when it opened the app. Anybody know what's going on here?
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[super viewDidLoad];
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; // whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters; // 100 m
[locationManager startUpdatingLocation];
_location = [locationManager location];
_coord.longitude = _location.coordinate.longitude;
_coord.latitude = _location.coordinate.latitude;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
_coord.longitude = _location.coordinate.longitude;
_coord.latitude = _location.coordinate.latitude;
printf("%f\n",self.coord.longitude);
printf("%f\n",self.coord.latitude);
}
You need to get the newLocation from the delegate method didUpdateLocationToLocation:fromLocation:. Also implement didFailWithError delegate method. It takes some time before you start getting updated locations, hence the delegate call.
The last location is usually cached, so it maybe wise to check location's timestamp and filter the old location out.
Edit:
This is the cleanest example I can provide. Start new project in Xcode, pick Single View application template, iPhone. Don't touch storyboard, just replace content of your ViewController.m with this and run in Simulator or device. If on Simulator, go to Debug and set some location and you will get coordinates in the console. I am also starting and stopping location updates when the view goes on or off screen.
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
#property (strong, nonatomic) CLLocationManager *locationManager;
#end
#implementation ViewController
#pragma mark - Location Manager delegate methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if ([newLocation.timestamp timeIntervalSinceNow] >= -300.0) {
NSLog(#"updated location with latitude %f longitude %f", newLocation.coordinate.longitude, newLocation.coordinate.latitude);
}
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.locationManager startUpdatingLocation];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.locationManager stopUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if(error.code == kCLErrorDenied) {
// alert user
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Access to location services is disabled"
message:#"You can turn Location Services on in Settings -> Privacy -> Location Services"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
} else if(error.code == kCLErrorLocationUnknown) {
NSLog(#"Error: location unknown");
} else {
NSLog(#"Error retrieving location");
}
}
#pragma mark - Location Manager getter
- (CLLocationManager *)locationManager
{
if (!_locationManager) {
_locationManager = [[CLLocationManager alloc] init];
_locationManager.delegate = self;
_locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
_locationManager.distanceFilter = 60.0;
}
return _locationManager;
}
#end
I have a location app that had the following method in the header of the ViewController.m file for the past couple of days:
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
However, I just deleted the above out of my code and the app still runs 100% fine. I don't understand how this is possible when the xcode documentation clearly says that the purpose of this method is to "tell the delegate when new location data is available."
The only thing I can think of is that it says "new location data" and that the above method is already setup in the CoreLocation.h file that I imported, and therefore already available for my use and has already stored the data.
Just want to make sure I understand the theory behind all of this before I move on.
Thank you for the help in clearing this up.
Here is my entire ViewController.m code(with the method still included):
#import "ViewController.h"
#import <CoreLocation/CoreLocation.h>
#interface ViewController () <CLLocationManagerDelegate>
//This tells the delegate that new location data is available. Manager is the object that updates the event, and the locations object is where the array of location data is stored.
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.gpsLM = [[CLLocationManager alloc]init];
NSLog(#"Location services enabled: %u",[CLLocationManager authorizationStatus]);
[self.gpsLM startUpdatingLocation];
self.gpsLM.delegate = self;
CLLocation * currentLocation = self.gpsLM.location;
NSLog(#"Your current location is: %#", currentLocation);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(IBAction)gpsButton{
CLLocation * currentLocation = self.gpsLM.location;
self.gpsLabel.text = [NSString stringWithFormat:#"Your Location is %#", currentLocation];
NSLog(#"Location services enabled: %u",[CLLocationManager authorizationStatus]);
NSLog(#"Your current location is: %#", currentLocation);
}
#end
iOS checks if your class is capable of receiving the data with something like:
if ( [delegate respondsToSelector:#selector(didUpdateLocations:)] ){
[delegate performSelector:#selector(didUpdateLocations:) withArgs:....]
}
So if your delegate doesn't implement the method, then it doesn't attempt to send it.
I've been trying to use startMonitoringForRegion for while, but experiencing problems to capture enter/exit events. When I launch the app on simulator and moved to the location I specified, I get 1 enter event, but enter events never triggered again. Can somebody let me know if I'm doing correctly?
test.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface EWViewController : UIViewController<CLLocationManagerDelegate>
{
CLLocationManager *locman;
}
#end
test.m
- (void)viewDidLoad
{
if(locman == nil)
locman = [[CLLocationManager alloc]init];
locman.delegate = self;
CLLocationCoordinate2D coord = CLLocationCoordinate2DMake(37.787359, -122.408227);
CLRegion *region = [[CLRegion alloc]initCircularRegionWithCenter:coord radius:1000.0 identifier:#"SF"];
[locman startMonitoringForRegion:region desiredAccuracy:kCLLocationAccuracyKilometer];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void) locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
NSLog(#"ENTER");
}
- (void) locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
NSLog(#"EXIT");
}
I have been using region monitoring for a geofence feature in my app for about 6 months and I have found it to be very precise. Once you have everything wired up correctly, it can be used to track enter and exit events quite well.
While you can get even better and more precise readings from -didUpdateToLocation, you will have to trade off battery life to get it. If you only need occasional location updates, it should be fine. If you need constant monitoring for specific locations, region monitoring is the way to go.
I have found that -startMonitoringForSignificantLocation is not accurate at all and not very practical. It relies solely on cell tower transitions and triangulation. It also can't be used to test in the simulator for this very reason. Hope some of this information helps you out.
Yes it works, but it is very very unprecised for the current moment. (I tested it in Russia)
I recommend you using this instead:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;