简体   繁体   English

跨多个视图使用CoreLocation的最佳方法

[英]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. 我的应用程序中有两个视图,一个是一般视图,其中CoreLocation在用户在视图中执行其他操作时计算用户位置。 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. 用户在触摸按钮时访问第二个视图,允许他们使用mapview和MapKit更准确地定位自己,我希望此视图中的mapview显示CoreLocation已在第一个视图中识别的位置并继续根据另一个视图中CoreLocation的更新显示此位置。

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 ? 这是创建封装CoreLocation内容的单例并在视图中使用地图引用或使用通知的最佳方法吗? or to use some other better practice for my scenario ? 或者为我的场景使用其他一些更好的练习?

Thanks 谢谢

I have a couple of apps that use CoreLocation in multiple places. 我有几个在多个地方使用CoreLocation的应用程序。 From what I've read, you definitely want there to be just one instance of CLLocationManager . 从我读过的内容来看,你肯定希望只有一个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. 我假设,您希望一直加载CalculatingView ,并根据用户操作加载/卸载MapView

  2. Allocate and initialize a pointer to CLLocationManager inside CalculatingView . CalculatingView中分配并初始化指向CLLocationManager的指针。 This will provide location property and also call delegate messages. 这将提供位置属性并调用委托消息。 Since the CalculatingView is loaded and retained, this pointer is always working too. 由于加载并保留了CalculatingView ,因此该指针也始终有效。

  3. Set CLLocationManager 's delegate to be CalculatingView , which might also be called self , if this view has allocated and initialized CLLocationManager pointer. 如果此视图已分配并初始化CLLocationManager指针,则将CLLocationManager的委托设置为CalculatingView ,也可称为self

  4. Implement delegate methods of CLLocationManager , in CalculatingView CalculatingView中实现CLLocationManager的委托方法

  5. If you like to, you can have MapView to be allocated and initialized within CalculatingView . 如果您愿意,可以在CalculatingView中分配和初始化MapView But it's ok to have it in other places, as long as you can send message to MapView . 但只要你可以向MapView发送消息,就可以在其他地方使用它。 Make sure they are valid by checking if it's not nil or if it respondsToSelector . 通过检查它是否为零或是否响应ToSelector来确保它们有效。

  6. When the CLLocationManager 's delegate, which is CalculatingView receives messages, send a message to MapView . CLLocationManager的委托(即CalculatingView)接收消息时,向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 这就像转发消息一样,但MapView应该响应的消息不必是发送到CalculatingView的相同消息,就像来自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 通过检查MapView是否有效,这意味着如果它被加载以显示,您可以决定是否向MapView发送消息

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). 本质是决定哪个视图是否被加载,使用委托方法将消息发送(或中继)到其他指针(在本例中为MapView指针)。

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 单身是好的,但除非你要从多个地方使用CLLocationManager ,比如超过3~4个地方,我认为没有必要

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. 另外,Apple的LocateMe应用程序实例化了三次位置管理器。 So, by their example, having multiple LocationManagers might not be a problem. 因此,通过他们的例子,拥有多个LocationManagers可能不是问题。

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. 根据我的阅读,最佳做法是将CLLocationManager添加到App Delegate因为您可以从任何视图访问它。

Short sample code to put in your view where you need the CLLocationManager 简短的示例代码放在您需要CLLocationManager的视图中

....imports....

@implementation YourViewController

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

@end

Hop that helps. 跳帮助。

Maybe you should consider a MVC oriented approach. 也许你应该考虑一种面向MVC的方法。 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. 使用基本CLLocation属性定义一个简单的User类将是第一步。

@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. 它可以在app委托中创建。

Next create location services object for your app. 接下来为您的应用创建位置服务对象。 It will start the CLLocationManager, and give the location to your user. 它将启动CLLocationManager,并将位置提供给您的用户。 You may have to set the GPS accuracy, ignore frames you don't want, and implement basic LBS logic here. 您可能必须设置GPS准确度,忽略您不想要的帧,并在此处实现基本LBS逻辑。

At this point, you have a feature full app, without any UI. 此时,您有一个功能完整的应用程序,没有任何UI。 This is a good design in the way it can be reused and tested. 这是一种可以重复使用和测试的好设计。

Now stack your UI on top of that. 现在将您的UI叠加在其上。 Give your root controller a pointer to the User instance in your app delegate. 为您的根控制器提供指向应用程序委托中的User实例的指针。 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. 该控制器开始在viewDidLoad中观察用户的位置变化并做出相应的反应。

- (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. 在代码中创建多个CLLocationManager实例没有真正的代价。 The only side effect is that the api is asynchronous, thus you have to wait to get a valid location in your view controller. 唯一的副作用是api是异步的,因此你必须等待在视图控制器中获得一个有效的位置。 You can try to get the current location from the location manager on your viewDidLoad using locationManager.location API. 您可以尝试使用locationManager.location API从viewDidLoad上的位置管理器获取当前位置。
  • 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 ? 如果您重复使用您的视图并且您的app delegate没有位置管理器,该怎么办?

if you need more code, please ask. 如果您需要更多代码,请询问。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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