本文主要教你如何使用iOS 7 SDK多任務(wù)處理API–Background Fetch。我們生活在一個(gè)社交化的世界中,大部分用戶都安裝了幾個(gè)社交類app,但是每次用戶打開(kāi)app,他們必須要等待app加載更新才能看到跟更多最新的內(nèi)容,對(duì)于越來(lái)越?jīng)]耐心的用戶來(lái)說(shuō)這一點(diǎn)無(wú)疑令人非常痛苦,F(xiàn)在,iOS 7的后臺(tái)獲。˙ackground Fetch)可以很好地解決這個(gè)問(wèn)題,在用戶打開(kāi)應(yīng)用之前,app就能自動(dòng)更新獲取內(nèi)容。
以檢測(cè)流量的app為例來(lái)說(shuō)明Background Fetch如何工作。如果你會(huì)在每天早上查看應(yīng)用,我們假設(shè)在8:20 AM,,你的iOS app必須在當(dāng)時(shí)獲得信息,F(xiàn)在如果操作系統(tǒng)知道你將會(huì)在8:20 AM左右使用app,那么它可以提前獲得數(shù)據(jù),從而提供更好的用戶體驗(yàn)。
關(guān)于iOS 7多任務(wù)執(zhí)行更全面的概覽可參看我們的主題“
iOS 7 SDK: Multitasking Enhancements”。以下我們將會(huì)以一個(gè)實(shí)例工程來(lái)演示如何使用后臺(tái)獲。˙ackground Fetch)。
1.項(xiàng)目安裝
第一步是創(chuàng)建一個(gè)iOS 7項(xiàng)目,并選擇單視圖app,接著添加一些有用的屬性:
@property (nonatomic) NSMutableArray *objects;
@property (nonatomic) NSArray *possibleTableData;
@property (nonatomic) int numberOfnewPosts;
@property (nonatomic) UIRefreshControl *refreshControl;
NSMutablearray對(duì)象將會(huì)被用來(lái)在TableView中保存對(duì)象列表。在這個(gè)教程中,你將不能調(diào)用任何服務(wù)來(lái)獲得數(shù)據(jù)。相反,你將使用possibleTableData數(shù)組,并隨機(jī)從中選擇幾個(gè)對(duì)象。整個(gè)numberOfnewPosts代表新發(fā)布的內(nèi)容–每次進(jìn)行請(qǐng)求或者接收后臺(tái)獲取時(shí)可用。refrestControl是一個(gè)在更新任務(wù)時(shí)使用的控件。由于不在教程之內(nèi),所以本文不會(huì)在此展開(kāi)。
在Main.storyboard中,把ViewController改為UITableViewController,下一步,點(diǎn)擊UITableViewController,轉(zhuǎn)到Editor > Embed in > Navigation Controller。記得把自定義類設(shè)置為ViewController。然后轉(zhuǎn)至ViewController.m,第一步加載一些數(shù)據(jù)。以下代碼將會(huì)申請(qǐng)內(nèi)存并創(chuàng)建數(shù)據(jù)對(duì)象,創(chuàng)建一個(gè)標(biāo)題以及初始化refreshControl:
self.possibleTableData = [NSArray arrayWithObjects:@"Spicy garlic Lime Chicken",@"Apple Crisp II",@"Eggplant Parmesan II",@"Pumpkin Ginger Cupcakes",@"Easy Lasagna", @"Puttanesca", @"Alfredo Sauce", nil];
self.navigationItem.title = @"Delicious Dishes";
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:@selector(insertNewObject:) forControlEvents:UIControlEventValueChanged];
[self.tableView addSubview:self.refreshControl];
以上代碼將會(huì)產(chǎn)生一個(gè)提醒,因?yàn)槲覀儊G失了insertNewObject method。讓我們來(lái)解決它。該方法將會(huì)產(chǎn)生一個(gè)隨機(jī)數(shù),并且將從日期數(shù)組獲得對(duì)象相同的數(shù)據(jù),然后它將會(huì)通過(guò)新值來(lái)更新tableview。
- (void)insertNewObject:(id)sender
{
self.numberOfnewPosts = [self getRandomNumberBetween:0 to:4];
NSLog(@"%d new fetched objects",self.numberOfnewPosts);
for(int i = 0; i < self.numberOfnewPosts; i++){
int addPost = [self getRandomNumberBetween:0 to:(int)([self.possibleTableData count]-1)];
[self insertObject:[self.possibleTableData objectAtIndex:addPost]];
}
[self.refreshControl endRefreshing];
}
當(dāng)你添加以下方法時(shí),getRandomNumberBetween提醒將會(huì)被禁止:
-(int)getRandomNumberBetween:(int)from to:(int)to {
return (int)from + arc4random() % (to-from+1);
}
為了在 NSArray object上加載對(duì)象,我們需要執(zhí)行TableView委托函數(shù)。
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.objects.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.objects[indexPath.row];
if(indexPath.row < self.numberOfnewPosts){
cell.backgroundColor = [UIColor yellowColor];
}
else
cell.backgroundColor = [UIColor whiteColor];
return cell;
}
非常簡(jiǎn)單吧?如果運(yùn)行項(xiàng)目,你會(huì)看到一個(gè)類似下圖的界面:
2. Background Fetch
現(xiàn)在開(kāi)始創(chuàng)建Background Fetch功能,首先從Project開(kāi)始,接著是Capabilities,然后Put Background Modes ON,再選擇Background Fetch,如下圖所示:
但僅僅做這個(gè)是不夠的。默認(rèn)地,app不會(huì)調(diào)用后臺(tái)API,所以你需要在AppDelegate.m文件中把以下代碼添加至-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions method.
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
這個(gè)可以讓系統(tǒng)決定何時(shí)應(yīng)該展示新內(nèi)容,F(xiàn)在你的app已經(jīng)知道啟動(dòng)ackground fetch,讓我們告訴它要做些什么。方法-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler將會(huì)對(duì)你有所幫助。每當(dāng)執(zhí)行后臺(tái)獲取時(shí)該方法都會(huì)被調(diào)用,并且應(yīng)該被包含在AppDelegate.m文件中。以下是完整版本:
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;
id topViewController = navigationController.topViewController;
if ([topViewController isKindOfClass:[ViewController class]]) {
[(ViewController*)topViewController insertNewObjectForFetchWithCompletionHandler:completionHandler];
} else {
NSLog(@"Not the right class %@.", [topViewController class]);
completionHandler(UIBackgroundFetchResultFailed);
}
}
下一步你應(yīng)該也把ViewController頭文件放進(jìn)AppDelegate.m類。
#import "ViewController.h"
注意insertNewObjectForFetchWithCompletionHandler并沒(méi)有被創(chuàng)建,所以還需要在ViewController.h中聲明它。
- (void)insertNewObjectForFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
現(xiàn)在關(guān)注執(zhí)行文件,類似于之前insertNewObject調(diào)用的添加。我們使用completionHandler來(lái)和系統(tǒng)“交流”,并讓它告訴我們app是否現(xiàn)在獲取數(shù)據(jù),或者當(dāng)前是否有有效數(shù)據(jù)。
- (void)insertNewObjectForFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
NSLog(@"Update the tableview.");
self.numberOfnewPosts = [self getRandomNumberBetween:0 to:4];
NSLog(@"%d new fetched objects",self.numberOfnewPosts);
for(int i = 0; i < self.numberOfnewPosts; i++){
int addPost = [self getRandomNumberBetween:0 to:(int)([self.possibleTableData count]-1)];
[self insertObject:[self.possibleTableData objectAtIndex:addPost]];
}
/*
At the end of the fetch, invoke the completion handler.
*/
completionHandler(UIBackgroundFetchResultNewData);
}
完成代碼,現(xiàn)在我們模擬一個(gè)測(cè)試,并驗(yàn)證所有項(xiàng)目都能啟動(dòng)和運(yùn)行。
3. Simulated Background Fetch
如果想確定是否每件事都已經(jīng)配置好了,你需要編輯Schemes,在Schemes列表點(diǎn)擊Manage Schemes選項(xiàng),如下:
在Schemes管理區(qū)你可以復(fù)制app的scheme:
復(fù)制后scheme會(huì)在新窗口展示。你可在Options標(biāo)簽下更改它的名稱。選擇“Launch due to a background fetch event”框,并在所有窗口中點(diǎn)擊“OK”。
接著,使用復(fù)制的scheme運(yùn)行app。注意app不會(huì)在前臺(tái)打開(kāi),但是它應(yīng)該已經(jīng)獲得了一些內(nèi)容。如果打開(kāi)app,并且?guī)讉(gè)recipe已生效,那就說(shuō)明操作已經(jīng)成功了。為了使用后臺(tái)獲取功能,你也可以從Xcode菜單的Debug > Simulate Background Fetch開(kāi)始。