I all I wonder if anybody can help me once again? I have moved my location coding from my View controller into an NSObject. I have then called this from the App Delegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Updating Location
[Location sharedLocation];
//Timer for reloading the XML
recheckTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:#selector(recheckLocation) userInfo:nil repeats:YES];
return YES:
}
I have set a timer for when I want this process ran again
-(void)recheckLocation
{
//Updating Location
[Location sharedLocation];
NSLog(#"Timer Triggered");
}
The only thing is when the timer triggers the sharedlocation does not get updated again?? Please can anybody help in advance? Many thanks, Jon.
#import "Location.h"
#implementation Location
#synthesize locationManager;
- (id)init {
self = [super init];
if(self) {
self.locationManager = [CLLocationManager new];
[self.locationManager setDelegate:self];
[self.locationManager setDistanceFilter:500];//Metres
[self.locationManager setHeadingFilter:90];
[self.locationManager startMonitoringSignificantLocationChanges];
}
return self;
}
+ (Location*)sharedLocation {
static Location* sharedLocation;
if(!sharedLocation) {
#synchronized(sharedLocation) {
sharedLocation = [Location new];
}
}
return sharedLocation;
}
//LOCATION CODING
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError' %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]initWithTitle:#"Error" message:#"Failed to Get Your Current 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) {
//Resolve Web Address
webAddressResolved = [NSString stringWithFormat:#"XZYYFASDFA%f,%f.xml", currentLocation.coordinate.latitude, currentLocation.coordinate.longitude];
NSLog(#"Address Resolved %#", webAddressResolved);
}
//Stop Location Manager
[locationManager stopMonitoringSignificantLocationChanges];
}
Well what yo defined here is a singleton of Location and the purpose of shared location does not seem to update the location as it says in the code comments
what the sharedInstance does is return a reference that is once initialized and is used the same everywhere in the whole code.It gives you the location instance in return, which you are not retrieving anywhere and using it.You just call it but not use it.
Define a method to update location and call it after getting the memory from the location using
Location *sharedLoc=[Location sharedLocation];
and call the method to update the location as
[sharedLoc updateLocation];
Location.h
-(void)updateLocation;
in Location .m
-(void)updateLocation
{
//Code for updation purpose
}
Related
I am using MKReverseGeocoder (reversegeocoder) to retrieve user's current location. I am calling reversegeocoder in locationDidUpdatedToLocation method of CLLocation Manager.
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if(!reverseGeocoder )
{
NSLog(#"geocoder is nill");
reverseGeocoder=[[MKReverseGeocoder alloc] initWithCoordinate:[newLocation coordinate]];
reverseGeocoder.delegate=self;
[reverseGeocoder start];
NSLog(#"geocoder allocated");
}
else
{
NSLog(#"geocoder is not nill");
if(reverseGeocoder.querying)
{
//do nothing ;
}
else
[reverseGeocoder release];
}
}
.querying property is used to ensure that reversegeocoder should be released only when It has completed its query. But when application crashes within 3-4 seconds of running with error message
-[MKReverseGeocoder isQuerying]: message sent to deallocated instance
What am I missing here?
Thanks for any help in advance.
Could it be because you haven't set the geocoder's delegate to nil before releasing it? Or that you haven't nilled the pointer?
Try this:
if(reverseGeocoder.querying)
{
//do nothing ;
}
else
{
[reverseGeocoder setDelegate:nil];
[reverseGeocoder release];
reverseGeocoder = nil;
}
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 am creating an application in which i want to get the current location of the user where he is and display it on the map and when the user reaches the destination location from current location the destination location should also be pointed in the map along the direction of travel.
In my xib i have added a button & on action(showDirectionsToHere) of button i have called map
I have added the following code in my appdelegate but it gives me an error:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation{
[manager stopUpdatingLocation];
printf("\n Latitude = " "\n Longitude = " " ",[NSString stringWithFormat:#"%.7f",newLocation.coordinate.latitude],[NSString stringWithFormat:#"%.7f",newLocation.coordinate.longitude]);
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
CLLocationManager *locationManager = [[[CLLocationManager alloc]init]autorelease];
locationManager.delegate = self;
[locationManager startUpdatingLocation];
//[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];
return YES;
}
-(void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
printf("\nerror");
}
- (IBAction)showDirectionsToHere {
CLLocationCoordinate2D currentLocation = [self getCurrentLocation]; // LINE 1
NSString* url = [NSString stringWithFormat: #"http://maps.google.com/maps?saddr=old\%20Location&daddr=%f,%f", newLocation.latitude, newLocation.longitude];//Line 2
}
in line 1 of action(showDirectionsHere) i get error of invalid initializer
in Line 2 i get error that newLocation undeclared.
Please help me
NSString* url = [NSString stringWithFormat: #"http://maps.google.com/maps?saddr=old\%20Location&daddr=%f,%f", currentLocation.latitude, currentLocation.longitude];
Can you post the code for getCurrentLocation so that we can see what it returns.
The variable newLocation is undeclared. I think you meant currentLocation in the function.
I am new to iphone development.I am creating a map application.I have toolbar below the mapview with a button on it.On clicking the button it displays as an alert to load the current location.In my button click even i hava given code to find current location
-(IBAction) gosearch : (id) sender{
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
For me it is not displaying the alert.What should i do?Please help me out. Thanks.
You need to have your controller class implement protocol CLLocationManagerDeligate. This will mean that it gets notified of errors or when the location is posted (for example – locationManager:didUpdateToLocation:fromLocation:)
Then you can pass on the long/lat and radius of view required to the MapView
Make sure for the alert view it looks like this-
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Current Location" message:#"Show Current Location?" delegate:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"OK"];
[alert show];
and also
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
if (buttonIndex != [alertView cancelButtonIndex])
{
map.showsuserlocation = YES;
}
}
I'm not sure I fully understand your questions but here's what I have done to use the location manager.
First, I declare a class that implements CLLocationManagerDelegate
#interface GPSComponent <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *currentLocation;
}
Then, in the class I have:
- (id) init {
locationManager = [[CLLocationManager alloc] init];
// Provide the best possible accuracy (this is the default; just want to write some code).
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
// Must move at least 100 meters to get a new location update (default is get all notifications).
locationManager.distanceFilter = 100;
locationManager.delegate = self;
[locationManager startUpdatingLocation];
}
#pragma mark -
#pragma mark CLLocationManagerDelegate methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
// If you are about 400 miles south off the coast of Ghana, we might be ignoring your location information. We apologize.
// This is a lazy way to check for failure (in which case the struct is zeroed out).
if((fabs(newLocation.coordinate.latitude) > 0.001) || (fabs(newLocation.coordinate.longitude) > 0.001)) {
NSLog(#"Got location %f,%f", newLocation.coordinate.latitude, newLocation.coordinate.longitude);
if (currentLocation != nil) {
[currentLocation release];
}
currentLocation = newLocation;
[currentLocation retain];
}
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Location Manager error");
}
Then, to display a map with the user's location:
// Pull out the longitude and latitude and invoke google maps
- (IBAction)mapItButtonPressed {
NSString *url = [NSString stringWithFormat: #"http://maps.google.com/maps?q=%f,%f", (float)currentLocation.coordinate.latitude, (float)currentLocation.coordinate.longitude];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:url]];
}
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