iPhone need updated location in multiple controller
I am trying to get the user's current location on multiple controller, they are part of navigation controller, tabbarcontroller, presentmodel controller, so basically I really cannot do something like self.navigationcontroller or self.tabBarController.
What i did was I created a LocationHelper and a LocationHelperDelegate
@protocol LocationHelperDelegate
@required
- (void)locationUpdate:(CLLocation *)location; // Our location updates are sent here
- (void)locationError:(NSError *)error; // Any errors are sent here
@end
@interface LocationHelper : NSObject <CLLocationManagerDelegate>{
CLLocationManager *locationManager;
CLLocation *currentLocation;
id delegate;
}
@property (nonatomic, retain) CLLocation *currentLocation;
@property (nonatomic, retain) CLLocationManager *locationManager;
@property (nonatomic, assign) id delegate;
@end
And then in my .m file I do the following
-(id) init {
self = [super init];
if(self != nil){
self.locationManager = [[[CLLocationManager alloc] init] autorelease];
self.locationManager.delegate = self;
}
return self;
}
- (void)locationManager:(CLLocationMana开发者_如何学运维ger *)manager didUpdateToLocation:(CLLocation
*)newLocation fromLocation:(CLLocation *)oldLocation {
if([self.delegate conformsToProtocol:@protocol(LocationHelperDelegate)]) {
[self.delegate locationUpdate:newLocation];
}
}
And then now this is what I am doing in all my controller where I need a location update. In the init method
LocationHelper* locationHelper = [[LocationHelper alloc]init];
locationHelper.delegate = self;
[locationHelper.locationManager startUpdatingLocation];
and then I implement
- (void)locationUpdate:(CLLocation *)location {
latitude = location.coordinate.latitude;
longitude = location.coordinate.longitude;
[locationHelper.locationManager stopUpdatingLocation];
}
I am 100% sure this is not the right way for doing it, but I have no clue how I should be doing this. Basically all I need is to do startUpdatingLocation once and then all my controller get a notification for locationUpdate, and when every one has received the notification stopUpdatingLocation.
I was thinking about making the LocationHelper class has a singleton but then when all the controller gets the instance of it can they set them self as a delegate, that doesn't seems right because delegate is one of the instance variable in the LocationHelper and it can hold only one value.
So as you can see I am confused, please help.
The approach I took to catching responses from a multi-threaded network request was using NSNotificationCenter. It was unbelievable easy to implement and doesn't require you to keep a variable in a specific place, such as AppDelegate. This obviously makes things more flexible if you decide to refactor the code later on.
To dispatch a notification, you can use code like this. Note that we pass along custom data using the userInfo: paramater.
[[NSNotificationCenter defaultCenter] postNotificationName:@"requestFinished"
object:self
userInfo:resultDictionary];
To subscribe to be notified of a notification as above, use code like below. Not that the name: matches the postNotificationName: above. This is how you can dispatch and subscribe to multiple notifications, depending on your needs.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(requestFinishedHandler:)
name:@"requestFinished"
object:nil];
And here is a prototype of how to access the custom user data that is passed through to your selector: defined above. Because I may want to pass around multiple pieces of data, I sent through an NSDictionary.
- (void)requestFinishedHandler:(NSNotification *)notification
{
resultDictionary = [notification userInfo];
}
A piece of data that should only be represented once (like "my current location", of which you can have only one) should be someplace that can only exist once, like a singleton.
You already have one perfectly good singleton that you're already using. There are those who will disagree with me on this (and God knows they've got good reasons to), but for this sort of data I don't have the first problem keeping it all in my App Delegate.
When the app launches, in the App Delegate, I'll fire up a CLLocationManager with the App Delegate itself as the location manager's delegate. I'll keep the returned CLLocation as a named property of the delegate (say "currentLocation"), and overwrite it as often as I get updates from the locationManager.
Then in my various view controllers I can say:
MyAppDelegate *del = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
CLLocation *current = del.currentLocation;
This way all your location getting/management/storage happens in one place that you can get to from anywhere in your app, and it keeps everything nice and clean
EDIT: In answer to the question "By key-value observing, do you mean notifications", the answer is NO. They're completely different things.
In any of your view controllers--probably in viewDidLoad--you can say:
MyAppDelegate *del = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[del addObserver:self forKeyPath:@"currentLocation" options:0 context:nil];
And then implement:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
MyAppDelegate *del = (MyAppDelegate *)object;
CLLocation *hereIAm = del.currentLocation;
// and then do whatever with that
}
You got a bunch of details about the change that just happened on that key in the parameters of that method, but it's probably simpler just to reach back up to the delegate and snatch out the value you're looking for.
Probably want to remove that observer in viewDidUnload:
MyAppDelegate *del = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[del removeObserver:self forKeyPath:@"currentLocation"];
Your location helper should be a singleton (here's a good example: http://www.galloway.me.uk/tutorials/singleton-classes/)
You should use notifications rather than delegates. The location helper singleton should send notifications when it has a new location, any interested controller should subscribe to those notifications.
精彩评论