与前一篇介绍app(主动)在后台运行长时间的任务不同,这次是app(被动)让IOS唤醒启动模式
一般情况,都是打开运行app,然后让app刷新,才能看到新内容,但是这种新的唤醒机制是让app在后台就完成刷新任务,当用户打开app时,新内容已经呈现出
前提:项目设置-Capabilities-Background Modes:Background fetch 勾选中
方法:
//设置唤醒时间
- (void)setMinimumBackgroundFetchInterval:(NSTimeInterval)minimumBackgroundFetchInterval
//执行后台获取数据操作
- (void)application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
e.g.
AppDelegate.h
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@property (nonatomic, strong) NSMutableArray *allNewsItems;
@end
AppDelegate.m
#import "AppDelegate.h"
#import "NewsItem.h" //自定义对象NewsItem 有两属性 NSDate *date , NSString *text;
@implementation AppDelegate
//初始化数组
- (NSMutableArray *) allNewsItems{
if (_allNewsItems == nil){
_allNewsItems = [[NSMutableArray alloc] init];
/* Pre-populate the array with one item */
NewsItem *item = [[NewsItem alloc] init];
item.date = [NSDate date];
item.text = [NSString stringWithFormat:@"News text 1"];
[_allNewsItems addObject:item];
}
return _allNewsItems;
}
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//设置唤醒时间,默认UIApplicationBackgroundFetchIntervalNever,稍后要执行performFetchWithCompletionHandler
[application setMinimumBackgroundFetchInterval: UIApplicationBackgroundFetchIntervalMinimum];
return YES;
}
// 后台获取数据
- (void) application:(UIApplication *)application
performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))
completionHandler{
BOOL haveNewContent = NO;
[self fetchNewsItems:&haveNewContent];
if (haveNewContent){
completionHandler(UIBackgroundFetchResultNewData); // 成功获取到新数据
} else { // UIBackgroundFetchResultFailed 失败
completionHandler(UIBackgroundFetchResultNoData); // 没有新数据
}
}
//参数BOOL带*,表示作为地址存值
//模拟从服务器获取数据,若是0则无数据,1为有数据
- (void) fetchNewsItems:(BOOL *)paramFetchedNewItems{
if (arc4random_uniform(2) != 1){ //arc4random_uniform(n): [0,n) 随机数
if (paramFetchedNewItems != nil){
*paramFetchedNewItems = NO;
}
return;
}
[self willChangeValueForKey:@"allNewsItems"]; //KVO模式 willChangeValueForKey -> didChangeValueForKey
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"];
}
.....
@end
@interface TableViewController : UITableViewController
@end
-TableViewController.m
#import "TableViewController.h"
#import "AppDelegate.h"
#import "NewsItem.h"
@interface TableViewController ()
@property (nonatomic, weak) NSArray *allNewsItems; //注意,这里是用weak
@property (nonatomic, assign) BOOL mustReloadView;
@end
@implementation TableViewController
- (void)viewDidLoad
{
[super viewDidLoad];
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
self.allNewsItems = appDelegate.allNewsItems; //因为是weak,所以若appDelegate.allNewsItems后续指向空时,self.allNewsItems也随之
//注册以接收KVO通知
[appDelegate addObserver:self
forKeyPath:@"allNewsItems"
options:NSKeyValueObservingOptionNew
context:NULL];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleAppIsBroughtToForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
//当keyPath对应的值改变时。。必须先注册(addObserver:forKeyPath:options:context)
//在AppDelegate.m文件中fetchNewsItems时,有didChangeValueForKey,所以在值改变时此处会执行
- (void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{
if ([keyPath isEqualToString:@"allNewsItems"]){
if ([self isBeingPresented]){
[self.tableView reloadData];
} else {
self.mustReloadView = YES;
}
}
}
- (void) handleAppIsBroughtToForeground:(NSNotification *)paramNotification{
if (self.mustReloadView){
self.mustReloadView = NO;
[self.tableView reloadData];
}
}
#pragma mark - Table view data source
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return self.allNewsItems.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier
forIndexPath:indexPath];
NewsItem *newsItem = self.allNewsItems[indexPath.row];
cell.textLabel.text = newsItem.text;
return cell;
}
//取消相关注册
- (void) dealloc{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate removeObserver:self forKeyPath:@"allNewsItems"];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
@end