typedef NS_ENUM(NSUInteger, UIBackgroundFetchResult) {
UIBackgroundFetchResultNewData,
UIBackgroundFetchResultNoData,
UIBackgroundFetchResultFailed
} NS_ENUM_AVAILABLE_IOS(7_0);
Итак, если iOS приказывает вашему приложению обновить контент новыми данными, вы пытаетесь получить эти данные, но их в наличии не оказывается, то вам придется вызвать обработчик завершения и передать ему значение UIBackgroundFetchResultNoData. Так вы сообщите iOS, что для обновления информации вашего приложения не нашлось новых данных, и система сможет откорректировать свой алгоритм планирования и механизмы искусственного интеллекта. В результате система станет вызывать приложение не столь часто. iOS действительно очень толково справляется с такими задачами. Допустим, вы приказываете iOS вызвать приложение в фоновом режиме, чтобы оно могло получить новый контент. Но сервер не дает приложению каких-либо обновлений, и в течение целой недели приложение активизируется на пользовательском устройстве в фоновом режиме, но так и не может получить новых данных и неизменно передает блоку завершения вышеупомянутого метода значение UIBackgroundFetchResultNoData. В таком случае совершенно очевидно, что iOS стоит будить это приложение не так часто. Так можно будет более экономно расходовать вычислительную мощность и, соответственно, заряд батареи.
В этом разделе мы собираемся написать простое приложение, которое будет получать с сервера новости. Чтобы не перегружать этот пример слишком сложным серверным кодом, мы просто сымитируем серверные вызовы. Сначала создадим класс NewsItem, который имеет в качестве свойств дату и текст:
#import
@interface NewsItem: NSObject
@property (nonatomic, strong) NSDate *date;
@property (nonatomic, copy) NSString *text;
@end
У этого класса не будет никакой реализации, поэтому всю информацию он будет нести только в свойствах. Возвращаемся к делегату нашего приложения и определяем изменяемый массив новостей. Таким образом мы сможем закрепить этот массив в контроллере табличного вида и отобразить новостные элементы:
#import
@interface AppDelegate: UIResponder
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSMutableArray *allNewsItems;
@end
Теперь выполним отложенное выделение массива. Это означает, что массив не будет выделяться и инициализироваться до тех пор, пока приложение прямо к нему не обратится. Так экономится память. Как только массив будет выделен, мы добавим к нему один новый элемент:
#import «AppDelegate.h»
#import «NewsItem.h»
@implementation AppDelegate
— (NSMutableArray *) allNewsItems{
if (_allNewsItems == nil){
_allNewsItems = [[NSMutableArray alloc] init];
/* Заранее записываем в массив один элемент */
NewsItem *item = [[NewsItem alloc] init];
item.date = [NSDate date];
item.text = [NSString stringWithFormat:@"News text 1"];
[_allNewsItems addObject: item];
}
return _allNewsItems;
}
Теперь реализуем в нашем приложении метод, который будет имитировать вызов сервера. Можно сказать, что здесь мы играем в орлянку. Точнее, метод случайным образом генерирует одно из двух чисел — 0 или 1. Получив 1, мы считаем, что на сервере есть новые новостные материалы для загрузки. Получив 0, считаем, что такая новая информация на сервере отсутствует. Если мы получили 1, то сразу после этого добавляем в список новый элемент:
— (void) fetchNewsItems:(BOOL *)paramFetchedNewItems{
if (arc4random_uniform(2)!= 1){
if (paramFetchedNewItems!= nil){
*paramFetchedNewItems = NO;
}
return;
}
[self willChangeValueForKey:@"allNewsItems"];
/* Генерируем новый элемент */
NewsItem *item = [[NewsItem alloc] init];
item.date = [NSDate date];
item.text = [NSString stringWithFormat:@"News text %lu",
(unsigned long)self.allNewsItems.count + 1];
[self.allNewsItems addObject: item];
if (paramFetchedNewItems!= nil){
*paramFetchedNewItems = YES;
}
[self didChangeValueForKey:@"allNewsItems"];
}
Логический параметр указателя этого метода сообщит нам, появилась ли новая информация, добавленная в массив.
Теперь реализуем механизм фонового обновления в делегате нашего приложения, так, как было объяснено ранее:
— (void) application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))
completionHandler{
BOOL haveNewContent = NO;
[self fetchNewsItems:&haveNewContent];
if (haveNewContent){
completionHandler(UIBackgroundFetchResultNewData);
} else {
completionHandler(UIBackgroundFetchResultNoData);
}
}
Отлично. В контроллере нашего табличного вида отслеживаем изменения массива новостных элементов в делегате приложения. Как только содержимое массива изменится, мы обновим табличный вид. Но будем делать это с умом. Если приложение работает в фоновом режиме, то действительно следует обновить табличный вид. Но если приложение работает в фоновом режиме, отложим обновление до тех пор, пока табличный вид не перейдет в приоритетный режим:
Читать дальше
Конец ознакомительного отрывка
Купить книгу