CLLocation may not respond to setDistanceFilter - iphone

I'm a newbie to programming for iPhone, I'm following along this book.
I'm stuck at the example in Chapter 4, Delegation and Core Location.
Here's the code I've written so far:
WhereamiAppdelegate.h
#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#interface WhereamiAppDelegate : NSObject <UIApplicationDelegate, CLLocationManagerDelegate> {
UIWindow *window;
CLLocation *locationManager;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#end
And here is the implementation file:
I have only included the changes that I've made.
The entire file is here.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Create location manager.
locationManager = [[CLLocation alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[locationManager startUpdatingLocation];
[self.window makeKeyAndVisible];
return YES;
}
- (void)dealloc
{
[locationManager setDelegate:nil];
[_window release];
[super dealloc];
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
NSLog(#"%#",newLocation);
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
NSLog(#"Couldn't find loaction %#",error);
}
XCode gives me a warning that says CLLocation may not respond to setDistanceFilter and other similar warnings.
I am clueless here, I have followed the book line to line.
I think that I haven't implemented a necessary protocol or something.
Can someone please tell me what I'm doing wrong and how I should proceed further.

The class CLLocation is not the same as CLLocationManager. The former represents one location, while the latter is the manager class that handles configuring location updates for your application.

Things like setDistanceFilter: are undocumented parts of system APIs. They may change without warning in future versions of iOS (any), and they also disqualify your app from being in AppStore, but if you're fine with that, no problem... if Apple really wanted to hide those things, they wouldn't be findable by just making a for-loop on a method-table.
BTW, the difference between CLLocation and CLLocationManager is irrelevant for your situation, because the code actually runs and does the right thing, so, you are sending the correct messages to the correct objects.

Related

Integrating GPS to my application

I am following a tutorial to integrate GPS to my application. I want to display the Latitude and Longitude values in the viewDidLoad method. According to the tutorial they have displayed it from another method. But i need it to be displayed in viewDidLoad. How can i modify the following code to display it in viewDidLoad ?
The HelloThereController.h view controller
#import "MyCLController.h"
#interface HelloThereViewController : UIViewController <MyCLControllerDelegate> {
MyCLController *locationController;
}
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
The HelloThereController.m view controller
#import "HelloThereViewController.h"
#implementation HelloThereViewController
- (void)viewDidLoad {
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
//I need to print the latitude and logitude values here..
}
My MyCLController.h class
#protocol MyCLControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface MyCLController : NSObject {
CLLocationManager *locationManager;
id delegate;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, assign) id delegate;
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
#end
My MyCLController.m class
#import "MyCLController.h"
#implementation MyCLController
#synthesize locationManager;
#synthesize delegate;
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation
{
[self.delegate locationUpdate:newLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error
{
[self.delegate locationError:error];
}
- (void)dealloc {
[self.locationManager release];
[super dealloc];
}
#end
If this view controller loads as soon as the app loads, you can't.
it takes time for the location manager to get gps updates.
you'll need to display some ui component that lets the user know you're getting the location, such as UIActivityIndicatorView, and setup another method for displaying the coordinates when you get them.
In general you can accelerate the process sacrificing some accuracy setting the desiredAccuracy property. According to the documentation the values are:
kCLLocationAccuracyBestForNavigation
kCLLocationAccuracyBest
kCLLocationAccuracyNearestTenMeters
kCLLocationAccuracyHundredMeters
kCLLocationAccuracyKilometer
kCLLocationAccuracyThreeKilometers
Anyway you are interested in the first location, so still according to the documentation:
When requesting high-accuracy location data, the initial event delivered by the location
service may not have the accuracy you requested. The location service delivers the initial
event as quickly as possible. It then continues to determine the location with the accuracy
you requested and delivers additional events, as necessary, when that data is available.
You can try starting the location manager in the AppDelegate didFinishLaunchingWithOptions to have some more time before the view appears. As said by Frederick Cheung, locationManager.location can be nil, so it's better do the operations in the location manager delegate.

CLLocationManager not calling any delegate methods

First off, the disclaimer is I'm targeting iOS 5, so that very well may be the source of my issues, but if not...
I'm trying to write a simple class that manages location updates through CoreLocation. However, I see some pretty strange behavior. I have a custom class which basically wraps CLLocationManager and the delegate methods. This is the interface:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#protocol CLZipCodeFetcherDelegate
#optional - (void)didReceiveZipCode:(NSString *)zipCode;
#end
#interface CLZipCodeFetcher : NSObject <CLLocationManagerDelegate> {
id <CLZipCodeFetcherDelegate> delegate;
CLLocationManager *locationManager;
}
#property (strong, readwrite) id <CLZipCodeFetcherDelegate> delegate;
#property (strong, read write) CLLocationManager *locationManager;
- (void)getZipCode;
#end
and the implementation (ignore the zip code related stuff- that's what the class is eventually meant to do, but right now I'm just trying to get some coordinates back from CoreLocation):
#import "CLZipCodeFetcher.h"
#implementation CLZipCodeFetcher
#synthesize delegate, locationManager;
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.distanceFilter = 10.0f; // we don't need to be any more accurate than 10m
self.locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
self.locationManager.purpose = #"Retrieve zip code";
}
return self;
}
- (void)getZipCode {
[self.locationManager startUpdatingLocation];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog(#"Received location");
}
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
NSLog(#"Location failed");
}
#end
And then I initialize an instance of the class in my view controller and call the method:
CLZipCodeFetcher *zipCodeFetcher = [[CLZipCodeFetcher alloc] init];
[zipCodeFetcher getZipCode];
Now, when I run this, the app takes a moment to load, and then pops up the alert dialog asking for permission to let the app use location services. However, as soon as it appears, it immediately disappears (too fast to let me hit the allow or deny button), and nothing happens (no delegate methods are called). If I then go into the Location Settings of the device, it indeed shows 'Off' for my app. When I turn it on manually from that screen and then go to try the app again, no alert dialog appears, but still nothing happens. Neither of my debug messages are logged. The behavior is the same on both the simulator and my iPhone 4.
So basically, anyone have any idea why? I've looked through all the similar threads, and many issues were related to memory management, but I don't think that'd be a problem here since ARC should be managing my CLLocationManager object, right?
P.S. Also, I did add the CoreLocation framework to my project, and I get no code errors or warnings, but is there anything else I need to do before using CoreLocation in my app?
ARC is deallocating your newly created object after the getZipCode method call.
I have not used ARC yet so I'm not sure of your syntax in the header (readwrite vs. read write).
But I would put an NSLog(#" my loc manager is %#", self.locationManager); inside of getZipCode just to make sure you've got one and it's not being released before it has a chance to do anything.

iPhone corelocation framework limitation?

fellas,
I am developing a application in which I need functionality to ask user for their location more than once, what happening is when user allowed it once to use his location and when he navigate to another section it's not asking him to get his location, it's taking it from already cached location.
is that possible to ask user multiple time for his approval to get his location?
Any help appreciated.
Cheers,
Amit
You don't need to get permission multiple times.
To begin getting updates, you call:
[locationManager startUpdatingLocation];
Until you call [locationManager stopUpdatingLocation] you will get continuous location updates.
So, you need to implement the delegate method to say what happens when you get a new location. This delegate method could do something as simple as save the location to a class variable for later use.
The delegate function you need to implement is:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {}
I should caution you here. It is battery intensive to constantly run the GPS (you'll kill the device in about 2.5 hours if you are requesting very accurate reading as fast as possible). So, what you should probably do is get a fix when the user turns the app on, and then call stopUpdatingLocation.
Then, in your app, have a "Locate Me" button, which would turn on the LocationManager, get a fix, and then turn off the LocationManager again. You might want to keep polling for a location until you get a good location.horizontalAccuracy
I suggest you implement an NSObject subclass, which implements the LocationManagerDelegate protocol. Then, this object would be shared across multiple view controllers. Here is a simple implementation of a central gpsController.
So, this would be gpsController.h:
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>
#interface gpsController : NSObject <CLLocationManagerDelegate> {
CLLocationManager *locationManager;
CLLocation *lastReading;
}
- (id)init;
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, retain) CLLocation *lastReading;
#end
And then the following is gpsController.m:
#import "gpsController.h"
#implementation gpsController
#synthesize locationManager, lastReading;
- (id)init {
if(self = [super init]) {
[[self locationManager] startUpdatingLocation];
self.lastReading = nil;
}
return self;
}
- (CLLocationManager *)locationManager {
if (locationManager) return locationManager;
locationManager = [[CLLocationManager alloc] init];
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
locationManager.delegate = self;
return locationManager;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
self.lastReading = newLocation;
}
According to iPhone Programming: The Big Nerd Ranch Guide, CLLocationManagers return the cached, last found device location first. Their sample code bails out of locationManager:didUpdateToLocation:fromLocation if the didUpdateToLocation timestamp is more than 3 minutes old, assuming it to be from the cache. That seems a pretty long time between valid updates, but maybe only by doing some testing would one know.
Maybe you could persist the timestamp between messages to see if you're still being served location data from the cache, or increment a counter for each call to locationManager:didUpdateToLocation:fromLocation and only ever use odd numbered calls or some other increment...

iPhone GPS Location

I want to get my longitude and latitude on iPhone in objective C. Can any one guide me how to get these coordinates programmatically?
#import <Foundation/Foundation.h>
#class CLLocationManager;
#interface CLLocationController : NSObject {
CLLocationManager *locationManager;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#end
When i write above code is shows me following errors
/Hab/Folder/Classes/CLLocationController.m:10:30: error: CLLocationManager.h: No such file or directory
/Hab/Folder/Classes/CLLocationController.m:21: warning: receiver 'CLLocationManager' is a forward class and corresponding #interface may not exist
/Hab/Folder/Classes/CLLocationController.m:22: error: accessing unknown 'delegate' component of a property
Use the CLLocationManager, set an object as the delegate and start getting updates.
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
[self.locationManager startUpdatingLocation];
Then implement the delegate:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation *)oldLocation {
NSLog([NSString stringWithFormat:#"%3.5f", newLocation.coordinate.latitude]);
NSLog([NSString stringWithFormat:#"%3.5f", newLocation.coordinate.longitude]);
}

iPhone Help: Odd Memory Leak In CoreLocation Framework

I've been working to iron out memory leaks in my program and I'm down to a few stragglers. The strange thing is that they're coming from when I use CoreLocation to get a gps location. The code is properly returning the location, but it's leaking all over the place: CFHTTPMessage, CFURLConnection, CFURLRequest, CFURLResponse, GeneralBlock-16,-32,-48, HTTPRequest, etc... Could anyone please guide me how to fix this?
Initialization of MyCLController
locationController = [[MyCLController alloc] init];
locationController.delegate = self;
[locationController.locationManager startUpdatingLocation];
Do some things and get a call back through the delegate:
[locationController release];
MyCLController.h:
#import <Foundation/Foundation.h>
#protocol MyCLControllerDelegate
#required
- (void)locationUpdate:(CLLocation *)location;
- (void)locationError:(NSError *)error;
#end
#interface MyCLController : NSObject {
CLLocationManager *locationManager;
id delegate;
}
#property (nonatomic, retain) CLLocationManager *locationManager;
#property (nonatomic, assign) id delegate;
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation;
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error;
#end
MyCLController.m:
#import "MyCLController.h"
#implementation MyCLController
#synthesize locationManager;
#synthesize delegate;
- (id) init {
self = [super init];
if (self != nil) {
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self; // send loc updates to myself
}
return self;
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
[locationManager stopUpdatingLocation];
[self.delegate locationUpdate:newLocation];
}
- (void)locationManager:(CLLocationManager *)manager
didFailWithError:(NSError *)error {
[self.delegate locationError:error];
}
- (void)dealloc {
[super dealloc];
}
#end
You need to release the LocationManager. Make sure that you set its delegate to NULL prior to releasing. And also, it's not a good idea to just return the first result. Make sure horizontal accuracy is not < 0 and is also below some threshold, like 5000 meters. And to make it more robust, you might want to add a timer to make it stop after a given amount of time, if it couldn't find your location accurately enough.
you never release locationController