【问题标题】:iOS re-check location on load from backgroundiOS从后台重新检查加载位置
【发布时间】:2011-11-16 11:22:31
【问题描述】:

我正在构建一个应用程序,它会根据您当前的位置显示结果数据。

目前,我正在使用UIViewControllerviewDidLoad 方法来启动CLLocationManager 并获取当前位置。一旦我的位置与我想要的准确度相匹配,我就会向我的网络服务发出请求以获取结果并将其转储到UITableView

我的问题是当您关闭应用程序时(尽管它仍在后台运行)。如果您要开车去另一个城镇,请重新打开应用程序,数据不会更新并继续显示您旧位置的结果。

基本上当UIViewController从后台加载时,我需要能够检查用户的位置,如果他们移动了很长的距离,更新我的UITableView的内容。

但是,由于从后台加载应用程序时不会触发UIViewControllerviewDidAppear,所以我不确定我可以使用哪种方法。

我知道stopMonitoringSignificantLocationChanges 方法会在找到新位置时唤醒您的应用程序。但是,这似乎有点 OTT,因为我只需要在应用加载后知道。

除了使用stopMonitoringSignificantLocationChanges 方法之外,还有其他选择吗?

【问题讨论】:

    标签: objective-c ios geolocation core-location cllocationmanager


    【解决方案1】:

    您可以注册您的视图以获取通知。对于需要跟踪应用程序状态的视图,我使用这个方便的超类。

    @implementation BackgroundAwareObject
    
    -init
    {
        if(self=[super init])
        {
            NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
            [center addObserver:self selector:@selector(notifyApplicationDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
            [center addObserver:self selector:@selector(notifyApplicationWillEnterForeground:) name: UIApplicationWillEnterForegroundNotification object:nil];
            [center addObserver:self selector:@selector(notifyApplicationDidFinishLaunching:) name: UIApplicationDidFinishLaunchingNotification object:nil];
            [center addObserver:self selector:@selector(notifyApplicationDidBecomeActive:) name: UIApplicationDidBecomeActiveNotification object:nil];
            [center addObserver:self selector:@selector(notifyApplicationWillResignActive:) name: UIApplicationWillResignActiveNotification object:nil];
            [center addObserver:self selector:@selector(notifyApplicationDidReceiveMemoryWarning:) name: UIApplicationDidReceiveMemoryWarningNotification object:nil];
            [center addObserver:self selector:@selector(notifyApplicationWillTerminate:) name: UIApplicationWillTerminateNotification object:nil];
        }
        return self;
    }
    
    -(void)notifyApplicationDidEnterBackground:(NSNotification*)n
    {
        [self applicationDidEnterBackground:[UIApplication sharedApplication]];
    }
    
    -(void)notifyApplicationWillEnterForeground:(NSNotification*)n
    {
        [self applicationWillEnterForeground:[UIApplication sharedApplication]];
    }
    
    -(void)notifyApplicationDidFinishLaunching:(NSNotification*)n
    {
        [self application:[UIApplication sharedApplication] didFinishLaunchingWithOptions: [n userInfo]];
    }
    
    -(void)notifyApplicationDidBecomeActive:(NSNotification*)n
    {
        [self applicationDidBecomeActive:[UIApplication sharedApplication]];
    }
    
    -(void)notifyApplicationWillResignActive:(NSNotification*)n
    {
        [self applicationWillResignActive:[UIApplication sharedApplication]];
    }
    
    -(void)notifyApplicationDidReceiveMemoryWarning:(NSNotification*)n
    {
        [self applicationDidReceiveMemoryWarning:[UIApplication sharedApplication]];
    }
    
    -(void)notifyApplicationWillTerminate:(NSNotification*)n
    {
        [self applicationWillTerminate:[UIApplication sharedApplication]];
    }
    
    -(void)configurationChanged
    {
        // User has update application configuration panel
    
    }
    
    - (void)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
    {    
        // Override point for customization after application launch.  
    
    }
    
    
    - (void)applicationWillResignActive:(UIApplication *)application 
    {
        /*
         Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
         Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
         */
    }
    
    
    - (void)applicationDidEnterBackground:(UIApplication *)application 
    {
        /*
         Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
         If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
         */
        _background = YES;
    }
    
    
    - (void)applicationWillEnterForeground:(UIApplication *)application 
    {
        /*
         Called as part of  transition from the background to the active state: here you can undo many of the changes made on entering the background.
         */
    }
    
    
    - (void)applicationDidBecomeActive:(UIApplication *)application 
    {
        /*
         Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
         */
        _background = NO;
    }
    
    
    /**
     applicationWillTerminate: saves changes in the application's managed object context before the application terminates.
     */
    - (void)applicationWillTerminate:(UIApplication *)application
    {
    }
    
    // try to clean up as much memory as possible. next step is to terminate app
    - (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
    {
    }
    
    -(void)dealloc
    {
        [[NSNotificationCenter defaultCenter]removeObserver:self];
        [super dealloc];
    }
    
    @end
    

    【讨论】:

    • 看起来不错。我会试一试。我认为您应该在 GitHub 上发布此内容,以便您可以收到有关如何扩展它或将其保留为可共享资源的 cmets。感谢分享。
    【解决方案2】:

    在您的AppDelegate.m 中,您必须预定义此方法(就像您在 Xcode 中启动项目时最初创建的模板中一样) -

    - (void)applicationDidBecomeActive:(UIApplication *)application
    {
        /*
         Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
         */
    }
    

    正如描述所说,当应用程序即将激活时,iOS 会自动调用此方法。在这里你可以得到最新的位置做进一步的处理。

    【讨论】:

    • 一旦我从那里获得了更新的位置,有没有办法让我的 UIViewController 的位置发生变化?
    • 您可以在此处导入您的 UIViewController.h 文件并将该位置传回或将位置变量设为单例(即,将其作为应用程序委托的一部分)。其实有很多种方法...
    • 好的,谢谢。这样做,与马克亚当斯建议的答案相比有什么优势。就个人而言,他似乎更容易,因为这一切都在 UIView 中进行管理。
    • 是的,这更干净。这就是这些方法存在的原因。这完全符合您的需求。你也可以做标记建议的,但为什么呢?这样更干净...
    • 好的,我只是想实现这个方法。我只是有点难以将值传递回我的 UIViewController。为了能够触发更新,我需要在我的 UIViewController 上调用一个方法,同时将位置传回。如何从 AppDelegate 访问我的 UIViewController 的活动实例?
    【解决方案3】:

    您可以在-viewDidLoad 中注册以接收来自 UIApplication 的通知。您可能对UIApplicationDidBecomeActiveNotification 感兴趣。注册通知很容易。

    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
    }
    

    -viewDidLoad 中,我们将自己添加为UIApplicationDidBecomeActiveNotification 的观察者,并指定在收到特定通知时要调用的选择器。

    - (void)applicationDidBecomeActive:(NSNotification *)notification
    {
        // Kick off your CLLocationManager
        [self updateCurrentLocation];
    }
    
    - (void)viewDidUnload
    {
        [super viewDidUnload];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
    }
    

    最后,请记住在视图卸载时移除自己作为此通知的观察者。以这种方式平衡对 NSNotificationCenter 的 addObserver/removeObserver 调用是一种很好的做法。

    【讨论】:

    • 感谢您的回答,完美运行。这似乎比使用 AppDelegate 方法更好,因为它将所有内容都保存在同一个 UIViewController 中。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    相关资源
    最近更新 更多