Использование UIApplicationBackgroundRefreshStatusDidChangeNotification без соответствующего метода делегата

Мне кажется, что UIApplicationBackgroundRefreshStatusDidChangeNotification, представленный в iOS 7, бесполезен без поддержки метода делегата 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 станет Доступным через приложение Настройки> Общие> Фоновое обновление приложения. Я чувствую, что в UIApplicationDelegate должен был быть соответствующий метод делегата, чтобы сообщить приложению об этом изменении, чтобы приложение могло восстановить все, что ему нужно.

Либо я что-то упускаю (ранее существовавший API), либо у инженеров Apple SDK есть какие-то другие/ограниченные намерения в отношении использования этого уведомления. Пожалуйста посоветуй.




Ответы (2)


в идеале вам никогда не придется проверять этот параметр. Похоже, вы ходите по фону, выбирая неправильный путь. Когда приложение свернуто, система будет периодически пробуждать ваше приложение и разрешать ему выполнять задачи. Из вашего кода вы хотите обновить местоположение. первое место, с которого нужно начать, здесь, используя этот метод делегата, который вызывается, когда приложение просыпается для фоновой выборки

/// Приложения с фоновым режимом "выборка" могут получить возможность получать обновленный контент в фоновом режиме или когда это удобно для системы. Этот метод будет вызываться в таких ситуациях. Вы должны вызвать fetchCompletionHandler, как только закончите выполнение этой операции, чтобы система могла точно оценить свою мощность и стоимость данных. - (void)application:(UIApplication *)application PerformFetchWithCompletionHandler:(void (^)(результат UIBackgroundFetchResult))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, немедленно приведет к сбою вашего приложения. Узнайте больше о блоках из документации Apple здесь https://developer.apple.com/library/ios/documentation/cocoa/conceptual/ProgrammingWithObjectiveC/WorkingwithBlocks/WorkingwithBlocks.html

также взгляните на вызов [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval: ]; который указывает минимальное время, которое должно пройти между операциями фоновой выборки.

Вероятно, вы бы добавили это в метод didFinishLaunchingWithOptions приложения-делегата вашего приложения.

надеюсь, это поможет вам.

person dubemike    schedule 09.10.2013

Для получения уведомлений необходимо зарегистрироваться:

[[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, обновления местоположения, которые вы хотите работать в фоновом режиме, должны начинаться на переднем плане. Таким образом, это означает, что как только пользователь выключит фоновое обновление для приложения, обновления местоположения прекратятся, и единственное, что может перезапустить обновления местоположения, — перезапустить обновления местоположения на переднем плане! В этом случае делегат будет бесполезен, поскольку он не может перезапускать обновления местоположения в фоновом режиме. Это по дизайну.

person Khaled Barazi    schedule 02.12.2013
comment
Этот блок/обработчик уведомлений вызывается только тогда, когда настройки выключены OFF (поскольку приложение находится в фоновом режиме и работает из-за служб определения местоположения). Но, как сказано в моем вопросе, обработчик НЕ запускается, когда фоновое обновление возвращается в состояние ON (помните, что приложение все еще находится в фоновом режиме, но очевидно, что оно сейчас не работает). Вот почему я считаю, что должен быть какой-то механизм для информирования приложения, например. метод делегата приложения, который вызывается всякий раз, когда этот параметр фонового обновления изменяется в фоновом режиме. - person Ashok; 02.12.2013
comment
Хорошо, я согласен, что это может быть «как задумано». Я считаю, что application:performFetchWithCompletionHandler - это единственный ограниченный (не гарантированный) вариант восстановления состояния приложения, как сказал @michael. - person Ashok; 02.12.2013