I'm stuck :(
In my application I require an update from CLLocationManager every time it gets an update to a new position. I am not using XIB/NIB files, everything I coded I have done programmatically. To the code:
the .h
#interface TestViewController : UIViewController
UILabel* theLabel;
#property (nonatomic, copy) UILabel* theLabel;
#end
the .m
...
-(void)loadView{
....
UILabel* theLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0,0.0,320.0,20.0)];
theLabel.text = #"this is some text";
[self.view addSubView:theLabel];
[theLabel release]; // even if this gets moved to the dealloc method, it changes nothing...
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Location: %#", [newLocation description]);
// THIS DOES NOTHING TO CHANGE TEXT FOR ME... HELP??
[self.view.theLabel setText:[NSString stringWithFormat: #"Your Location is: %#", [newLocation description]]];
// THIS DOES NOTHING EITHER ?!?!?!?
self.view.theLabel.text = [NSString stringWithFormat: #"Your Location is: %#", [newLocation description]];
}
...
Any ideas, or help?
(this was all hand jammed so please forgive me if it looks kinda gacked) I can provide more info if needed.
Your loadView method is wrong. You do not set the instance variable properly but instead you generate a new local variable. Change it to the following by omitting the UILabel * and do not release it because you want to keep a reference around to the label to set the text later.
-(void)loadView{
....
theLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0,0.0,320.0,20.0)];
theLabel.text = #"this is some text";
[self.view addSubView:theLabel];
}
- (void) dealloc {
[theLabel release];
[super dealloc];
}
Then later directly access the variable like this:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Location: %#", [newLocation description]);
theLabel.text = [NSString stringWithFormat: #"Your Location is: %#", [newLocation description]];
}
Are you synthesizing theLabel in your .m file...? If not, you need to, I believe.
Related
I am developing an iPhone app which uses location services and runs in background.This app displays latitude and longitude exactly when it runs on IOS6.But if i run the same app on IOS7, sometimes it shows latitude and longitude exactly, sometimes -1 and -1. I'm not understanding this behaviour on IOS7. what may be the reason for this behaviour?
In order to simulate a location, select the iOS Simulator Debug -> Location menu option and select either one of the pre-defined locations or journeys (such as City Bicycle Ride), or Custom Location… to enter a specific latitude and longitude.
This code worked for me.
Creating the CLLocationManager Object
The next task is to implement the code to create an instance of the CLLocationManager class. Since this needs to occur when the view loads, an ideal location is in the view controller’s viewDidLoad method in the LocationViewController.m file:
- (void)viewDidLoad {
[super viewDidLoad];
_locationManager = [[CLLocationManager alloc] init];
_locationManager.desiredAccuracy = kCLLocationAccuracyBest;
_locationManager.delegate = self;
[_locationManager startUpdatingLocation];
_startLocation = nil;
}
Implementing the Action Method
-(void)resetDistance:(id)sender
{
_startLocation = nil;
}
Implementing the CLLocationManager Method
#pragma mark -
#pragma mark CLLocationManagerDelegate
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSString *currentLatitude = [[NSString alloc]
initWithFormat:#"%+.6f",
newLocation.coordinate.latitude];
_latitude.text = currentLatitude;
NSString *currentLongitude = [[NSString alloc]
initWithFormat:#"%+.6f",
newLocation.coordinate.longitude];
_longitude.text = currentLongitude;
NSString *currentHorizontalAccuracy =
[[NSString alloc]
initWithFormat:#"%+.6f",
newLocation.horizontalAccuracy];
_horizontalAccuracy.text = currentHorizontalAccuracy;
NSString *currentAltitude = [[NSString alloc]
initWithFormat:#"%+.6f",
newLocation.altitude];
_altitude.text = currentAltitude;
NSString *currentVerticalAccuracy =
[[NSString alloc]
initWithFormat:#"%+.6f",
newLocation.verticalAccuracy];
_verticalAccuracy.text = currentVerticalAccuracy;
if (_startLocation == nil)
_startLocation = newLocation;
CLLocationDistance distanceBetween = [newLocation
distanceFromLocation:_startLocation];
NSString *tripString = [[NSString alloc]
initWithFormat:#"%f",
distanceBetween];
_distance.text = tripString;
}
In the End Try this method
Try this method to get continuous updated latitude and longitude
(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CLLocation *location_updated = [locations lastObject];
NSLog(#"updated coordinate are %#",location_updated);
}
Use this method for getting location continuously use this method
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
location_updated = [locations lastObject];
NSLog(#"updated coordinate are %#",location_updated);
}
may be you are using this method
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
This method has been Deprecated in iOS 6.0
What is the easiest way to pass a var into another function ?
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(#"%#", started);
}
I tried:
Defined a global vars:
extern NSString *started;
When I set the NSString directly and passing into another function, it works well:
-(void) startTracking:(CDVInvokedUrlCommand*)command {
started = #"testing";
}
But it doesn't work:
-(void) startTracking:(CDVInvokedUrlCommand*)command {
NSString* myarg = [command.arguments objectAtIndex:0]; // http://docs.phonegap.com/en/2.5.0/guide_plugin-development_ios_index.md.html#Developing%20a%20Plugin%20on%20iOS_writing_an_ios_cordova_plugin
started = myarg;
}
(I'm a objective-C beginner, don't understand it well)
EDIT: Seems like it only crashed when I put the app into background.
Depending on wether you are using ARC, you have to retain the object. You'll probably want to use a property on your class:
in your header:
#property(strong) NSString *started;
in implementation:
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
NSLog(#"%#", self.started);
}
-(void) startTracking:(CDVInvokedUrlCommand*)command {
self.started = #"testing";
}
-(void) startTracking:(CDVInvokedUrlCommand*)command {
NSString* myarg = [command.arguments objectAtIndex:0];
self.started = myarg;
}
Mate, seems like you want to track the date you started receiving location information.
How about doing it like this:
// Your .h file
#interface MyClass <CLLocationManagerDelegate>
{
BOOL hasStartedUpdatingLocation;
NSDate *startDate;
CLLocationManager *locationManager;
}
...
// Your .m file
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// ---------------------------------------------------------------
// if has NOT started updating location, record start date
// otherwise, do not execute this if statement
// ---------------------------------------------------------------
if(!hasStartedUpdatingLocation)
{
hasStartedUpdatingLocation = YES;
// this if statement should only execute once
startDate = [NSDate date]; // get the current date and time
}
else
{
// do something else
}
}
I am getting latitude, Longitude, Altitude, Accuracy, Speed from Location services.
I want to update all this information every 30 sec. For this purpose I've used a NSTimer:
[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(locationUpdate:) userInfo:nil repeats:YES];
which I've put in the viewDidLoad method. It shows an output first time, but the second time, when the timer invokes this, it shows this error:
2011-08-02 13:17:00.141 CoreLocationAssign[1120:207] This is location <__NSCFTimer: 0x4b200a0>
2011-08-02 13:17:00.142 CoreLocationAssign[1120:207] -[__NSCFTimer coordinate]: unrecognized selector sent to instance 0x4b200a0
2011-08-02 13:17:00.144 CoreLocationAssign[1120:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFTimer coordinate]: unrecognized selector sent to instance 0x4b200a0'
*** Call stack at first throw:
The code is below:
MyCLController.h
#implementation MyCLController
#synthesize locationManager;
#synthesize delegate;
- (id) init{
if (self!=nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[self.locationManager startUpdatingLocation];
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
//NSLog(#"Location: %#", [newLocation description]);
[self.delegate locationUpdate:newLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
// NSLog(#"Error: %#", [error description]);
[self.delegate locationError:error];
}
- (void)dealloc {
[self.locationManager release];
[super dealloc];
}
CoreLoactionController.h
- (void)viewDidLoad {
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(locationUpdate:) userInfo:nil repeats:YES];
[super viewDidLoad];
}
- (void)locationUpdate:(CLLocation *)location {
locationLable.text = [location description];
CLLocationCoordinate2D coordinate = [location coordinate];
NSLog(#"This is location %#",[location description]);
NSLog(#"Lattitude = %#",[NSString stringWithFormat:#"%f", coordinate.latitude]);
NSLog(#"Langitude = %#",[NSString stringWithFormat:#"%f", coordinate.longitude]);
NSLog(#"Altitude = %#",[NSString stringWithFormat:#"%gm", location.altitude]);
NSLog(#"horizontalAccuracy = %#",[NSString stringWithFormat:#"%gm", location.horizontalAccuracy]);
NSLog(#"verticalAccuracy = %#",[NSString stringWithFormat:#"%gm", location.verticalAccuracy]);
NSLog(#"Speed = %#",[NSString stringWithFormat:#"%gm", location.speed]);
}
How ccan I solve this problem? I want to update the location every 30 sec.
There are better solutions than using a timer. CoreLocation has built in features for deferred updates and a timer combined with normal CoreLocation will destroy phone battery. Try allowDeferredLocationUpdatesUntilDistanceTraveled:timeout:
https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/allowDeferredLocationUpdatesUntilTraveled:timeout:
In fact here :
- (void)locationUpdate:(CLLocation *)location
You're not receiving a CLLocation * but a NSTimer.
You should use the userInfo to transmit an object:
[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(locationUpdate:) userInfo:location repeats:YES];
and
-(void)locationUpdate:(NSTimer*) timer{
//probably
CLLocation *location = (CLLocation*)[timer userInfo];
//...
}
Timer-based location updates are horrible battery eaters.
CoreLocation can tell you when the location gets changed, no need for polling. 30 seconds is much too slow if I'm even walking, and it needlessly destroys the battery if my phone is lying near my bed unmoved for many hours.
I've defined this subclass of CLLocation
MyLocation.h
#interface MyLocation: CLLocation {
NSString *datum;
NSString *ellipsoid;
}
#property(nonatomic,retain) NSString *ellipsoid;
#property(nonatomic,retain) NSString *datum;
MyLocation.m
#synthesize datum,ellipsoid;
Now I get a CLLocation instance through the location manager delegate
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
//self.myPosition is a MyLocation myPosition;
self.myPosition = newLocation;
[myPosition setDatum: #"WGS 84"];
[myPosition setEllipsoid: #"WGS 84"];
}
When I do the self.myPosition = newLocation, I get an UNCAUGHT EXCEPTION and it dies
I've also tried this way with same results:
self.myPosition = (MyLocation *)newLocation;
newLocation is not an instance of ur subclass so doing that assignment or casting throws an error because it's an invalid cast, u should be seting the values of ur subclass that u want fromthe cllocation object something like
self.myPosition=[[MyLocation alloc] initWithCoordinate:newLocation.coordinate]
and so on
I already know how to use the CLLocationManager, so I could do it the hard way, with delegates and all that.
But I'd like to have a convenience method that just gets the current location, once, and blocks until it gets the result.
What I do is implement a singleton class to manage updates from core location. To access my current location, I do a CLLocation *myLocation = [[LocationManager sharedInstance] currentLocation]; If you wanted to block the main thread you could do something like this:
while ([[LocationManager sharedInstance] locationKnown] == NO){
//blocking here
//do stuff here, dont forget to have some kind of timeout to get out of this blocked //state
}
However, as it has been already pointed out, blocking the main thread is probably not a good idea, but this can be a good jumping off point as you are building something. You will also notice that the class I wrote checks the timestamp on location updates and ignores any that are old, to prevent the problem of getting stale data from core location.
This is the singleton class I wrote. Please note that it is a little rough around the edges:
#import <CoreLocation/CoreLocation.h>
#import <Foundation/Foundation.h>
#interface LocationController : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *currentLocation;
}
+ (LocationController *)sharedInstance;
-(void) start;
-(void) stop;
-(BOOL) locationKnown;
#property (nonatomic, retain) CLLocation *currentLocation;
#end
#implementation LocationController
#synthesize currentLocation;
static LocationController *sharedInstance;
+ (LocationController *)sharedInstance {
#synchronized(self) {
if (!sharedInstance)
sharedInstance=[[LocationController alloc] init];
}
return sharedInstance;
}
+(id)alloc {
#synchronized(self) {
NSAssert(sharedInstance == nil, #"Attempted to allocate a second instance of a singleton LocationController.");
sharedInstance = [super alloc];
}
return sharedInstance;
}
-(id) init {
if (self = [super init]) {
self.currentLocation = [[CLLocation alloc] init];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
[self start];
}
return self;
}
-(void) start {
[locationManager startUpdatingLocation];
}
-(void) stop {
[locationManager stopUpdatingLocation];
}
-(BOOL) locationKnown {
if (round(currentLocation.speed) == -1) return NO; else return YES;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
//if the time interval returned from core location is more than two minutes we ignore it because it might be from an old session
if ( abs([newLocation.timestamp timeIntervalSinceDate: [NSDate date]]) < 120) {
self.currentLocation = newLocation;
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
UIAlertView *alert;
alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[error description] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[alert release];
}
-(void) dealloc {
[locationManager release];
[currentLocation release];
[super dealloc];
}
#end
There is no such convenience and you shouldn't create your own. "Blocks until it gets the result" is extremely bad programming practice on a device like the iPhone. It can take seconds to retrieve a location; you should never make your users wait like that, and delegates ensure they don't.
There are no "convenience methods" unless you code them yourself, but you'd still need to implement the delegate methods in whatever custom code you use to make things "convenient."
The delegate pattern is there for a reason, and as delegates are a big part of Objective-C, I recommend you get comfortable with them.
I appreciated the answer by Brad Smith. Implementing it I discovered that one of the methods he employs is deprecated as of iOS6. To write code that will work with both iOS5 and iOS6, use the following:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations {
if (abs([[locations lastObject] timeIntervalSinceDate:[NSDate date]]) < 120) {
[self setCurrentLocation:[locations lastObject]];
}
}
// Backward compatibility with iOS5.
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSArray *locations = [NSArray arrayWithObjects:oldLocation, newLocation, nil];
[self locationManager:manager didUpdateLocations:locations];
}
I simplified and combined multiple answers to where the location is only updated if it's valid.
It also works under OSX as well as iOS.
This assumes the use-case where the current location is suddenly desired by the user. If it takes more than 100 ms in this example, it's considered an error. (Assumes the GPS IC &| Wifi (Apple's Skyhook clone) is already fired up and has a good fix already.)
#import "LocationManager.h"
// wait up to 100 ms
CLLocation *location = [LocationManager currentLocationByWaitingUpToMilliseconds:100];
if (!location) {
NSLog(#"no location :(");
return;
}
// location is good, yay
https://gist.github.com/6972228