Core Location Warning Issue - iphone

My core location works but I receive a warning at this line of code. locationManager.delegate = self; The warning is Assigning to 'id' from incompatible type 'phoneLocationViewController *const __strong'. How do I get rid of this warning? Here is my code
.h
#interface phoneLocationViewController : UIViewController {
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation;
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) CLLocation *currentLocation;
.m
#synthesize locationManager, currentLocation;
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation {
self.currentLocation = newLocation;
if(newLocation.horizontalAccuracy <= 100.0f) { [locationManager stopUpdatingLocation]; }
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
if(error.code == kCLErrorDenied) {
[locationManager stopUpdatingLocation];
} else if(error.code == kCLErrorLocationUnknown) {
// retry
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error retrieving location"
message:[error description]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (void)viewDidLoad
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self; (I GET THE WARNING HERE)
[locationManager startUpdatingLocation];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[locationManager stopUpdatingLocation];
[super viewDidUnload];
// Release any retained subviews of the main view.
}

Declare your class as implementing the protocol of the delegate of the location manager.
#interface phoneLocationViewController : UIViewController <CLLocationManagerDelegate> {

You should add the CLLocationManagerDelegate to your interface declaration.
#interface phoneLocationViewController : UIViewController <CLLocationManagerDelegate> {
....
}

Related

CLLocation Manager not updating new location

I am calling CLLocationManager and it's calling its delegate method as well. But my problem is, isn't updating its New Location after traveling 1 km.
Here's my code:
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationTimer=[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateLocation1:) userInfo:nil repeats:YES];
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
// Method did update location - Update location when location change
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// this method is calling after every 1 sec interval time..
}
-(void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
// this method is not calling once also after travelling around a km ....
}
What am I doing wrong?
You should be calling startUpdatingLocation or startMonitoringSignificantLocationChanges on the location manager for it to start checking for location changes and calling your delegate methods.
locationManager:didUpdateToLocation:fromLocation: is deprecated so you can expect it not to always be used.
If locationManager:didUpdateLocations: is being called then you are receiving location updates.
- (void)viewDidLoad
{
CLLocationManager *locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
locationManager.distanceFilter = kCLLocationAccuracyKilometer;
[locationManager startUpdatingLocation];
CLLocation *location = [locationManager location];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
//[manager stopUpdatingLocation];
CLLocationCoordinate2D coordinate_currentlocation = [newLocation coordinate];
float latitude_current = newLocation.coordinate.latitude;
float longitude_current = newLocation.coordinate.longitude;
}
Your first method
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
// this method is calling after every 1 sec interval time..
}
is used since iOS 6.
The second one is deprecated since iOS 6 and was used prior to iOS 6. You can use both methods, depending on the system version on the device your app is running at, by adding a helper method.
- (void) locationManager:(CLLocationManager *) manager didUpdateToLocation:(CLLocation *) newLocation fromLocation:(CLLocation *) oldLocation
{
[self locationManager:manager helperForLocation:newLocation];
}
- (void) locationManager:(CLLocationManager *) manager didUpdateLocations:(NSArray *) locations
{
if([locations count] > 0)
{
[self locationManager:manager helperForLocation:[locations objectAtIndex:[locations count] - 1]];
}
}
- (void) locationManager:(CLLocationManager *) manager helperForLocation:(CLLocation *) newLocation
{
// your code what to do with location goes here
}
The locations retrieved by iOS 6 are wrapped in a list and could be more than 1. In my example I take the last one and put it to my helper.
i have done this within my app with the use of this
myLocationManager = [[CLLocationManager alloc] init];
myLocationManager.delegate = self;
myLocationManager.desiredAccuracy = kCLLocationAccuracyBest;
[myLocationManager startUpdatingLocation];
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(#"didFailWithError: %#", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:#"Error" message:#"Failed to Get Your Location, Please turn on GPS and Restart The Application"delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[errorAlert show];
[errorAlert release];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.longitude];
[NSString stringWithFormat:#"%.8f", currentLocation.coordinate.latitude];
}
// Stop Location Manager
[myLocationManager stopUpdatingLocation];
}
-(void)postCurrentLocationOfDevice
{
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.distanceFilter = kCLDistanceFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[self.locationManager startUpdatingLocation];
self.locationManager.delegate = self;
}
-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
CURRENT_LOCATION = [locations objectAtIndex:0];
[self.locationManager stopUpdatingLocation];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
CURRENT_LOCATION = newLocation;
[self.locationManager stopUpdatingLocation];
}

Delegate Error with Core Location

I set up my own location retrieval class as documented in Apple's Core Location documentation.
MyCLControl.h:
#protocol MyCLControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface MyCLController : NSObject <MyCLControllerDelegate, CLLocationManagerDelegate> {
CLLocationManager *locationManager;
id <MyCLControllerDelegate> delegate;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (strong) id <MyCLControllerDelegate> delegate;
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
- (BOOL) connected;
#end
In MyCLController.m, the init and locationManager:didUpdateToLocation:fromlocation method:
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
//locationManager.desiredAccuracy = kCLLocationAccuracyKilometer;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
[self.delegate locationUpdate:newLocation];
}
The way I am calling it is as follows:
- (void)viewDidLoad {
MyCLController *locationController = [[MyCLController alloc] init];
locationController.delegate = locationController.self;
[locationController.locationManager startUpdatingLocation];
}
- (void)locationUpdate:(CLLocation *)location {
NSLog(#"%#", location);
}
I am getting a runtime error [MyCLController locationUpdate:]: unrecognized selector sent to instance once it hits [self.delegate locationUpdate:newLocation].
You have made the MyCLController a delegate of itself? Surely you meant to make the view the delegate instead?
You also need to be checking the delegate supports the method (even though it's required) using:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
if ([self.delegate respondsToSelector:#selector(locationUpdate:)])
{
[self.delegate locationUpdate:newLocation];
}
}

CLGeocoder only shows nearest apple store?

Is CLGeocoder just that coarse right now? I was expecting something relatively close to a street address. I'm testing on the 5.1 simulator and using ARC. I made a quick test project right now with the following if that helps:
- (IBAction)getLocationPressed {
if ([CLLocationManager locationServicesEnabled] &&
[CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized) {
[self.geoCoder reverseGeocodeLocation:self.locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
// Note: there is NO guarantee that the CLGeocodeCompletionHandler will be invoked on the main thread
dispatch_async(dispatch_get_main_queue(),^ {
NSLog(#"placemarks count: %d", [placemarks count]);
CLPlacemark *placemark = [placemarks objectAtIndex:0];
// Note: if a poor location is specified, there may be multiple placemarks for the given location
NSString *currentAddress = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
NSLog(#"I am currently at %#", currentAddress);
self.locationLabel.text = currentAddress;
});
}];
}
}
#pragma mark - CLLocationManager Delegate Methods
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
// do something...
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
if (error.code == kCLErrorDenied) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"this can not work without location services enabled"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
#pragma mark - Lifecycle Methods
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager.delegate = self;
self.locationManager.purpose = REASON_FOR_USING_LOCATION;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;//kCLLocationAccuracyNearestTenMeters;
[self.locationManager startUpdatingLocation];
}
Thanks
YESSSS! It turns out that I just wasn't enabling location in the simulator. It actually works if I test it on my device. Here's an example of with the full .m file if it helps anyone. I've set up a couple labels and a rounded rect button that you'll see from the code:
#define REASON_FOR_USING_LOCATION (#"to find the closest widget")
#interface ViewController () <CLLocationManagerDelegate>
#property (weak, nonatomic) IBOutlet UILabel *locationLabel;
#property (strong, nonatomic) CLLocationManager *locationManager;
#property (strong, nonatomic) CLGeocoder *geoCoder;
#end
#implementation ViewController
#pragma mark - Getters/Setters
#synthesize locationLabel = _locationLabel;
#synthesize locationManager = _locationManager;
#synthesize geoCoder = _geoCoder;
// lazily instantiate as required
- (CLGeocoder *)geoCoder {
if (!_geoCoder) _geoCoder = [CLGeocoder new];
return _geoCoder;
}
- (CLLocationManager *)locationManager {
if (!_locationManager) _locationManager = [CLLocationManager new];
return _locationManager;
}
#pragma mark - Target/Action Methods
- (IBAction)clearLocationPressed {
self.locationLabel.text = #"";
}
- (IBAction)getLocationPressed {
if ([CLLocationManager locationServicesEnabled] &&
[CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorized) {
[self.geoCoder reverseGeocodeLocation:self.locationManager.location completionHandler:
^(NSArray *placemarks, NSError *error) {
// Note: there is NO guarantee that the CLGeocodeCompletionHandler will be invoked on the main thread
dispatch_async(dispatch_get_main_queue(),^ {
NSLog(#"placemarks count: %d", [placemarks count]);
CLPlacemark *placemark = [placemarks objectAtIndex:0];
// Note: if a poor location is specified, there may be multiple placemarks for the given location
NSString *currentAddress = [[placemark.addressDictionary valueForKey:#"FormattedAddressLines"] componentsJoinedByString:#", "];
NSLog(#"I am currently at %#", currentAddress);
self.locationLabel.text = currentAddress;
});
}];
}
}
#pragma mark - CLLocationManager Delegate Methods
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
// do something...
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
if (error.code == kCLErrorDenied) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"this can not work without location services enabled"
delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
#pragma mark - Lifecycle Methods
- (void)viewDidLoad {
[super viewDidLoad];
self.locationManager.delegate = self;
self.locationManager.purpose = REASON_FOR_USING_LOCATION;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;//kCLLocationAccuracyNearestTenMeters;
[self.locationManager startUpdatingLocation];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)viewDidUnload {
[self setLocationLabel:nil];
[self setLocationManager:nil];
[self setGeoCoder:nil];
[super viewDidUnload];
}
#end

How to update location only when button is pressed

How can I make my application update location only when a button is pressed?
I have a button named "REFRESH". Everytime this button is pressed, I want to show my user their location. For example, 51 Bourke Street, Victoria.
However, I do not want to update my location regularly. I want to update its location only when the button is pressed, to save battery power.
What do you think? Am I doing it correctly?
I have these classes:
VoteViewController.h and VoteViewController.m
CoreLocationController.h and CoreLocationController.m
This is what I have:
VoteViewController.h class
#interface VoteViewController : UIViewController <CoreLocationControllerDelegate>
{
CoreLocationController *coreController;
}
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
- (void)geoReverseAddress:(MKPlacemark *)placeMark;
- (IBAction)refreshButtonPressed;
VoteViewController.m class
- (void)viewDidLoad
{
[super viewDidLoad];
coreController = [[CoreLocationController alloc] init];
coreController.delegate = self;
}
- (IBAction)refreshButtonPressed
{
NSLog(#"Refresh Button pressed");
label.text = [NSString stringWithString:#""];
[coreController.locationManager startUpdatingLocation];
}
- (void)locationUpdate:(CLLocation *)location
{
comments.text = [location description];
[coreController.locationManager stopUpdatingLocation];
}
- (void)locationError:(NSError *)error
{
comments.text = [error description];
[coreController.locationManager stopUpdatingLocation];
}
- (void)geoReverseAddress:(MKPlacemark *)placeMark
{
label.text = [NSString stringWithFormat:#"%# %#, %#", [placeMark subThoroughfare],
[placeMark thoroughfare], [placeMark locality]];
}
CoreLocationController.h class
#protocol CoreLocationControllerDelegate <NSObject>
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
- (void)geoReverseAddress:(MKPlacemark *)placeMark;
#end
#interface CoreLocationController : NSObject <CLLocationManagerDelegate, MKReverseGeocoderDelegate>
{
CLLocationManager *locationManager;
id delegate;
MKReverseGeocoder *reverse;
}
#property(nonatomic, retain) CLLocationManager *locationManager;
#property(nonatomic, retain) id delegate;
#end
CoreLocationController.m class
-(id) init
{
self = [super init];
if (self != nil)
{
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = kCLHeadingFilterNone;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(#"Update location");
[self.delegate locationUpdate:newLocation];
reverse = [[MKReverseGeocoder alloc] initWithCoordinate:[newLocation coordinate]];
reverse.delegate = self;
[reverse start];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
[reverse cancel];
[reverse release];
}
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark
{
[self.delegate geoReverseAddress:placemark];
[reverse cancel];
[reverse release];
}
When you first fire up CLLocationManager, you're very likely to get one stale location from the last time it ran. Once that's out of the way, you're going to start getting very inaccurate locations while the device uses WiFi sniffing and cell triangulation, while the GPS looks for a fix.
So in your didUpdateToLocation method, you probably want to throw away the first hit, and then test the .horizontalAccuracy value of your newLocation object for a low enough value to trust.
Apart from that, I don't see anything bad about what you've sent here. I'm not sure I'd go to the trouble of wrapping the location fetching work in its own class, I'd probably just do that out in my viewController. But that's a style choice. If you're reusing this functionality elsewhere, what you've got here is obviously the way to go.

How to calculate the average altitude through gps location manager in iphone

I want to calculate the maximum altitude, minimum altitude, and average altitude of the current location through CLLocationManager. I know how to calculate the altitude using the following code:
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface test : UIViewController <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *startingPoint;
IBOutlet UILabel *altitudeLabel;
}
#property (retain, nonatomic) CLLocationManager *locationManager;
#property (retain, nonatomic) CLLocation *startingPoint;
#property (retain, nonatomic) UILabel *altitudeLabel;
#end
//this is my test.h class
#import "test.h"
#implementation test
#synthesize locationManager;
#synthesize startingPoint;
#synthesize altitudeLabel;
#pragma mark -
- (void)viewDidLoad {
self.locationManager = [[CLLocationManager alloc] init];
[locationManager startUpdatingLocation];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)dealloc {
[locationManager release];
[startingPoint release];
[altitudeLabel release];
[super dealloc];
}
#pragma mark -
#pragma mark CLLocationManagerDelegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if (startingPoint == nil)
self.startingPoint = newLocation;
NSString *altitudeString = [[NSString alloc] initWithFormat:#"%gm", newLocation.altitude];
altitudeLabel.text = altitudeString;
[altitudeString release];
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSString *errorType = (error.code == kCLErrorDenied) ? #"Access Denied" : #"Unknown Error";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error gettingg location from Core Location" message:errorType delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[alert show];
[alert release];
}
#end
Through this I only get the altitude value, but I need to know how to calculate average altitude, minimum altitude, and maximum altitude. Does anyone know how to do this?
Instead of storing all the altitudes in an array as others have suggested, you could just store the current average/min/max and update it as you go.
int numUpdates = 0;
double averageAlt = 0.0;
double minAlt = DBL_MAX;
double maxAlt = DBL_MIN;
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
if (newLocation.altitude < minAlt) {
minAlt = newLocation.altitude;
}
if (newLocation.altitude > maxAlt) {
maxAlt= newLocation.altitude;
}
double sum = numUpdates * averageAlt;
sum+=newLocation.altitude;
numUpdates++;
averageAlt = sum / numUpdates;
}
I describe how to get min in the minAltitude method. I'll leave it to you to find max and average.
in .h:
NSMutableArray *altitudes;
in .m:
- (void) viewDidLoad {
[super viewDidLoad];
altitudes = [[NSMutableArray alloc] init];
}
- (void) dealloc {
[altitudes release];
[super dealloc];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[altitudes addObject:[NSNumber numberWithDouble:newLocation.altitude]];
}
- (double) minAltitude
{
double min = DBL_MAX;
double value;
NSNumber *altitude;
for (altitude in altitudes) {
value = [altitude doubleValue];
if (value < min) {
min = value;
}
}
return min;
}