简体   繁体   中英

best way to use CoreLocation across multiple views

I have two views in my app, one is a general view where CoreLocation works away calculating the users location while the user is doing other stuff in the view. The second view is accessed by the user when they touch a button allowing them to locate themselves more accurately using a mapview and MapKit, i would like the mapview in this view to show the location that CoreLocation has already identified in the first view AND to continue displaying this location based on updates from CoreLocation in the other view.

Is the best way here to create a singleton that encapsulates the CoreLocation stuff and have this referenced in the view with the map, or to use notifications ? or to use some other better practice for my scenario ?

Thanks

I have a couple of apps that use CoreLocation in multiple places. From what I've read, you definitely want there to be just one instance of CLLocationManager . It's worked great as a singleton for me.

Hope this helps!

If I were you, I would do it this way:

  1. Decide which view is going to be always loaded. I assume, you want CalculatingView is loaded all the time, and MapView will be loaded/unloaded based on the user action.

  2. Allocate and initialize a pointer to CLLocationManager inside CalculatingView . This will provide location property and also call delegate messages. Since the CalculatingView is loaded and retained, this pointer is always working too.

  3. Set CLLocationManager 's delegate to be CalculatingView , which might also be called self , if this view has allocated and initialized CLLocationManager pointer.

  4. Implement delegate methods of CLLocationManager , in CalculatingView

  5. If you like to, you can have MapView to be allocated and initialized within CalculatingView . But it's ok to have it in other places, as long as you can send message to MapView . Make sure they are valid by checking if it's not nil or if it respondsToSelector .

  6. When the CLLocationManager 's delegate, which is CalculatingView receives messages, send a message to MapView .

  7. It's like relaying messages, but the messages that MapView should respond to don't have to be the same messages sent to CalculatingView like delegate method calls from CLLocationManager

  8. By checking if MapView is valid, meaning if it's loaded to be displayed, you can decide to send messages to MapView or not

The essence is to decide which view is loaded consitently, to use delegate methods for sending(or relaying) messages to other pointers(in this cases, MapView pointer).

The singleton is good, but unless you are going to use CLLocationManager from multiple places, like more than 3~4 places, it's not that necessary, I think

Hope I didn't confuse you. Based on what you posted, it seems like this way can be simple solution for your goal. If I didn't catch your true intention, please let me know.

I am not sure this is the best way, but I've been setting up my main controller (the one that is loaded first) as a location manager delegate. When the location updates it fires off a notification with the new location as the notification object. Any controllers listening can then use that data however they need it.

As an aside, Apple's LocateMe app instantiates the location manager three times. So, by their example, having multiple LocationManagers might not be a problem.

From what I've read, best practice for this is to add CLLocationManager to your App Delegate as you can access it from any view.

Short sample code to put in your view where you need the CLLocationManager

....imports....

@implementation YourViewController

- (void)viewDidLoad {
   self.myLocationManager = [[UIApplication sharedApplication] delegate].yourLocationManagerVarName;
}

@end

Hop that helps.

Maybe you should consider a MVC oriented approach. From your description your are missing a model layer representation of your user. Defining a simple User class with a basic CLLocation property would be a first step.

@interface User {}
@property (nonatomic, retain) CLLocation *location;
@end

@implementation User
@synthesize location;
- (void)dealloc {
  self.location = nil;
  [super dealloc];
}
@end

The same instance of the User will be passed to your view controller. It may be created in the app delegate.

Next create location services object for your app. It will start the CLLocationManager, and give the location to your user. You may have to set the GPS accuracy, ignore frames you don't want, and implement basic LBS logic here.

At this point, you have a feature full app, without any UI. This is a good design in the way it can be reused and tested.

Now stack your UI on top of that. Give your root controller a pointer to the User instance in your app delegate. Your view controller pass this pointer to modals / navigations view controllers it creates.

This controller start observing User's location changes in their viewDidLoad and react accordingly.

- (void)viewDidLoad {
   [self observeValueForKeyPath:@"location" ofObject:self.user change:0 context:NULL];
}

Your view controller would also register for notification raised by your location services objects to display an alert to the user.

Based on other answers:

  • there is no real penalty to create multiple CLLocationManager instances in your code. The only side effect is that the api is asynchronous, thus you have to wait to get a valid location in your view controller. You can try to get the current location from the location manager on your viewDidLoad using locationManager.location API.
  • don't share stuff from your app delegate. This prevent code reuse. What if you reuse your views and you app delegate don't have a location manager ?

if you need more code, please ask.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM