與前一篇介紹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