iPhone需要在多个控制器中更新位置

时间:2011-04-13 15:31:00

标签: iphone objective-c cllocationmanager

我试图在多个控制器上获取用户的当前位置,它们是导航控制器,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并且它只能包含一个值。

所以你可以看到我很困惑,请帮忙。

3 个答案:

答案 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)

  1. 您的位置助手应该是一个单身人士(这是一个很好的例子:http://www.galloway.me.uk/tutorials/singleton-classes/

  2. 您应该使用通知而不是代理。位置帮助程序单例应该在有新位置时发送通知,任何感兴趣的控制器都应该订阅这些通知。

答案 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"];