4

感觉iOS 7 中引入的UIApplicationBackgroundRefreshStatusDidChangeNotification在不支持 UIApplication 委托方法的情况下用处不大。因为,当用户为我的应用打开后台刷新状态时,应用不会收到通知。

这是我的通知处理程序...

- (void)applicationDidChangeBackgroundRefreshStatus:(NSNotification *)notification
{
    NSLog(@"applicationDidChangeBackgroundRefreshStatus with notification info = %@ and refresh status = %d", notification, UIApplication.sharedApplication.backgroundRefreshStatus);

    if (UIApplication.sharedApplication.backgroundRefreshStatus == UIBackgroundRefreshStatusAvailable) {
//        if ([CLLocationManager locationServicesEnabled]) {
            [self.locationManager startUpdatingLocation];
//        }
    }
}

如上所述,当 UIBackgroundRegreshStatus通过 app Settings > General > Background App Refresh变为可用时,我想开始更新核心位置。我觉得 UIApplicationDelegate 中应该有一个适当的委托方法来让应用程序知道这个变化,以便应用程序可以重新建立它需要的一切。

要么我遗漏了某些东西(预先存在的 API),要么 Apple SDK 工程师对此通知的使用有一些其他/有限的意图。请指教。

4

2 回答 2

6

理想情况下,您永远不必检查该设置。看起来好像您正在以错误的方式绕过背景。随着应用程序的最小化,系统将定期唤醒您的应用程序并允许它执行任务。从您的代码中,您想要更新位置。第一个开始的地方是这里,使用当应用程序被唤醒以进行后台提取时调用的这个委托方法

/// 具有“获取”后台模式的应用程序可能有机会在后台或系统方便时获取更新的内容。在这些情况下将调用此方法。您应该在执行完该操作后立即调用 fetchCompletionHandler,以便系统可以准确估计其功率和数据成本。- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler NS_AVAILABLE_IOS(7_0);

这就是你使用它的方式,在你的应用程序委托实现中,定义方法体如下

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{

    NSLog(@"APP IS AWAKE FOR A BACKGROUND FETCH");
    //do all the work you want to do 

//once done, its important to call the completion hadler, otherwise the system will complain
          completionHandler(UIBackgroundFetchResultNewData);

 }

但是,由于您正在更新具有自己的委托的位置,因此您只希望在委托返回时调用完成处理程序,而不是在此之前调用。调用完成处理程序将使您的应用程序重新进入睡眠状态。由于完成处理程序是一个块对象,它可以像任何其他对象一样被传递。一种方法如下:在应用程序委托头文件中,定义一个块对象:

void (^fetchCompletionHandler)(UIBackgroundFetchResult);

然后在您的 performFetchWithCompletionHandler 中有:

-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    fetchCompletionHandler = completionHandler;

    NSLog(@"APP IS AWAKE FOR A BACKGROUND FETCH");
    //do all the work you want to do 
            [self.locationManager startUpdatingLocation];


 }

在某个适当的时间,在您的位置委托方法返回后,您调用

fetchCompletionHandler (UIBackgroundFetchResultNewData);

请务必检查您的 fetchCompletionHandler 是否为非 nil,当 nil 时调用它会立即使您的应用程序崩溃。在此处阅读有关苹果文档块的更多信息https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html

也看看调用 [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval: ]; which 指定后台提取操作之间必须经过的最短时间。

您可能会将其放入您的应用程序委托应用程序 didFinishLaunchingWithOptions 方法中。

希望这可以帮助你。

于 2013-10-09T08:48:48.053 回答
5

您需要注册通知:

[[NSNotificationCenter defaultCenter]
 addObserverForName:UIApplicationBackgroundRefreshStatusDidChangeNotification
 object: [UIApplication sharedApplication]
 queue:nil
 usingBlock:^(NSNotification* notification){
     NSLog(@"Just changed background refresh status because of this notification:%@",notification);
 }];

如果您的应用程序正在运行,您将获得此输出,然后您切换并禁用后台应用程序刷新。

> Just changed background refresh status because of this notification:NSConcreteNotification 0x165657e0 {name = UIApplicationBackgroundRefreshStatusDidChangeNotification; object = <UIApplication: 0x16668670>}

您显然可以选择不同的队列。此外,这不必在应用程序委托中。任何班级都可以收听此通知。

回顾 WWDC 会议,他们说这在 DP 种子 1 中不可用。我不确定这现在是否不是应用程序委托方法,因为他们没有得到它,或者这就是他们的意图,因为这更有可能被使用在应用程序委托之外(在您自己的模型或 VC 中)以侦听并调整正在更改的应用程序后台刷新权限。在后一种情况下,向注册它的任何人发出通知更有意义。

希望这可以帮助。

更新:根据 WWDC 2013 Core 位置视频,您想要在后台进行的位置更新必须从前台开始。因此,这意味着一旦用户关闭应用程序的后台刷新,位置更新将停止,唯一会重新启动位置更新的就是在前台重新启动位置更新!在这种情况下,委托将无用,因为它无法在后台重新启动位置更新。这是设计使然。

于 2013-12-02T12:22:05.413 回答