我试图在多个控制器上获取用户的当前位置,它们是导航控制器,tabbarcontroller,presentmodel控制器的一部分,所以基本上我真的不能做像self.navigationcontroller或self.tabBarController这样的事情。
我做的是创建了LocationHelper和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
然后在我的.m文件中,我执行以下操作
-(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 {
if([self.delegate conformsToProtocol:@protocol(LocationHelperDelegate)]) {
[self.delegate locationUpdate:newLocation];
}
}
然后现在这就是我在我需要位置更新的所有控制器中所做的事情。 在init方法
LocationHelper* locationHelper = [[LocationHelper alloc]init];
locationHelper.delegate = self;
[locationHelper.locationManager startUpdatingLocation];
然后我实现
- (void)locationUpdate:(CLLocation *)location {
latitude = location.coordinate.latitude;
longitude = location.coordinate.longitude;
[locationHelper.locationManager stopUpdatingLocation];
}
我100%肯定这不是正确的做法,但我不知道我应该怎么做。基本上我只需要执行startUpdatingLocation一次,然后我的所有控制器都会获得locationUpdate的通知,并且当每个控制器都收到通知stopUpdatingLocation时。
我正在考虑使LocationHelper类有一个单例,但是当所有控制器获取它的实例时,他们可以将它们自己设置为委托,这似乎不正确,因为委托是其中一个实例变量LocationHelper并且它只能包含一个值。
所以你可以看到我很困惑,请帮忙。
答案 0 :(得分:4)
我从多线程网络请求中捕获响应的方法是使用NSNotificationCenter。它实现起来难以置信,并且不要求您将变量保存在特定的位置,例如AppDelegate。如果您决定稍后重构代码,这显然会使事情变得更加灵活。
要发送通知,您可以使用此类代码。请注意,我们使用userInfo:paramater传递自定义数据。
[[NSNotificationCenter defaultCenter] postNotificationName:@"requestFinished"
object:self
userInfo:resultDictionary];
要订阅如上所述的通知,请使用如下代码。不是名称:匹配postNotificationName:上面。这是您根据需要发送和订阅多个通知的方式。
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(requestFinishedHandler:)
name:@"requestFinished"
object:nil];
以下是如何访问传递给选择器的自定义用户数据的原型:上面定义的。因为我可能希望传递多个数据,所以我发送了一个NSDictionary。
- (void)requestFinishedHandler:(NSNotification *)notification
{
resultDictionary = [notification userInfo];
}
答案 1 :(得分:2)
您的位置助手应该是一个单身人士(这是一个很好的例子:http://www.galloway.me.uk/tutorials/singleton-classes/)
您应该使用通知而不是代理。位置帮助程序单例应该在有新位置时发送通知,任何感兴趣的控制器都应该订阅这些通知。
答案 2 :(得分:2)
一段只能表示一次的数据(比如“我当前的位置”,你只能有一个)应该是一个只能存在一次的地方,就像单身一样。
你已经拥有一个你已经使用过的非常好的单身人士。有些人会对此表示不同意(上帝知道他们有充分的理由),但对于这类数据,我没有第一个问题,在我的App代表中保留所有这些。
当应用程序启动时,在App Delegate中,我将启动一个CLLocationManager,其中App Delegate本身作为位置管理器的委托。我将保留返回的CLLocation作为委托的命名属性(比如“currentLocation”),并在我从locationManager获取更新时经常覆盖它。
然后在我的各种视图控制器中,我可以说:
MyAppDelegate *del = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
CLLocation *current = del.currentLocation;
通过这种方式,您所有的位置获取/管理/存储都可以在您可以从应用中的任何位置访问的地方进行,并且可以保持一切美观和干净
编辑:在回答“通过键值观察,你的意思是通知”这个问题时,答案是否定的。他们是完全不同的东西。
在任何视图控制器中 - 可能在viewDidLoad中 - 您可以说:
MyAppDelegate *del = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[del addObserver:self forKeyPath:@"currentLocation" options:0 context:nil];
然后实施:
- (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
}
您在该方法的参数中获得了关于该键发生的更改的大量详细信息,但是回到代理并抢夺您正在寻找的值可能更简单。
可能想在viewDidUnload中删除该观察者:
MyAppDelegate *del = (MyAppDelegate *)[UIApplication sharedApplication].delegate;
[del removeObserver:self forKeyPath:@"currentLocation"];