CoreData用法二:NSFetchedResultsController例項操作與講解
阿新 • • 發佈:2019-02-06
學習了NSFetchedResultsController,才深深的體會到coredata的牛逼之處。原來Apple公司弄個新技術,不是平白無故的去弄,會給程式碼執行到來很大的好處。coredata不僅能讓我們大大的減少程式碼量,還最大化的提高執行效率。
就拿NSFetchedResultsController來說吧,他是和UITableView搭配使用的,可以最大化的提高UITableView的UI更新效率,比如我們刪除一個東西,只需要執行刪除資料庫裡面的一條資訊,然後通過配置NSFetchedResultsController的delegate方法,它自動會找到我們刪除的那條資訊,然後自動更新UI,最重要的時它不是整體的去更新UITableView,他是隻操作了需要刪除的哪一個,這就是他的偉大之處。
下面看看我寫的這個Demo吧
檔案結構:
將資料庫中得資料放到緩衝區中:
<span style="font-size:14px;">- (void)viewDidLoad { [super viewDidLoad]; NSFetchRequest * request = [[NSFetchRequest alloc] init]; NSEntityDescription * desption = [NSEntityDescription entityForName:TABLE_NAME inManagedObjectContext:[CoreDataManage GetManagedObjectContext]]; [request setEntity:desption]; NSSortDescriptor * desciptor = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES]; [request setSortDescriptors:[NSArray arrayWithObjects:desciptor, nil]]; //在CoreData為UITableView提供資料的時候,使用NSFetchedReslutsController能提高體驗,因為用NSFetchedReslutsController去讀資料的話,能最大效率的讀取資料庫,也方便資料變化後更新介面, //當我們設定好這個fetch的緩衝值的時候,我們就完成了建立 NSFetchedRequestController 並且將它傳遞給了fetch請求,但是這個方法其實還有以下幾個引數: // 對於managed object 內容,我們值傳遞內容。 //sectionnamekeypath允許我們按照某種屬性來分組排列資料內容。 //檔名的快取名字應該被用來處理任何重複的任務,比如說設定分組或者排列資料等。 NSFetchedResultsController * resultController = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:[CoreDataManage GetManagedObjectContext] sectionNameKeyPath:nil cacheName:nil]; resultController.delegate = self; self.fetchController = resultController; NSError * error = nil; //操作我們的 fetchedResultsController 並且執行performFetch 方法來取得緩衝的第一批資料。 if ([self.fetchController performFetch:&error]) { NSLog(@"success"); // NSLog(@"=======%@",[self.fetchController]) } else { NSLog(@"error = %@",error); } } </span>
配置UITableView
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { return 70; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { //section配置 // return [[self.fetchController sections] count]; //row配置 if ([[self.fetchController sections] count] > 0) { id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchController sections] objectAtIndex:section]; return [sectionInfo numberOfObjects]; } else { return 0; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString * mark = @"markIdentifer"; ContentCell * cell = [tableView dequeueReusableCellWithIdentifier:mark]; if (cell == nil) { cell = [[ContentCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:mark]; } Student * stu = (Student *)[self.fetchController objectAtIndexPath:indexPath]; [cell showModel:stu]; return cell; }
配置NSFetchedResultsController的delegate
<span style="font-size:14px;">//當資料發生變化時,點對點的更新tableview,這樣大大的提高了更新效率
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
switch (type) {
case NSFetchedResultsChangeInsert:
[self.contentTableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:newIndexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.contentTableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeMove:
{
[self.contentTableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
[self.contentTableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:newIndexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
}
break;
case NSFetchedResultsChangeUpdate:
{
ContentCell * cell1 = (ContentCell *)[self.contentTableView cellForRowAtIndexPath:indexPath];
Student * stu = (Student *)[controller objectAtIndexPath:indexPath];
[cell1 showModel:stu];
}
break;
default:
break;
}
}
//點對點的更新section
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
switch(type) {
case NSFetchedResultsChangeInsert:
[self.contentTableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.contentTableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
//此方法執行時,說明資料已經發生了變化,通知tableview開始更新UI
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.contentTableView beginUpdates];
}
//結束更新
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.contentTableView endUpdates];
}</span><span style="font-size:18px;">
</span>
新增一個刪除按鈕的操作,檢視效果
<span style="font-size:14px;">-(NSArray *)searchResult
{
NSFetchRequest * request = [[NSFetchRequest alloc] init];
NSEntityDescription * desption = [NSEntityDescription entityForName:TABLE_NAME inManagedObjectContext:[CoreDataManage GetManagedObjectContext]];
[request setEntity:desption];
NSError * error = nil;
NSArray * result = [[CoreDataManage GetManagedObjectContext] executeFetchRequest:request error:&error];
if (!error)
{
[result enumerateObjectsUsingBlock:^(Student * obj, NSUInteger idx, BOOL *stop) {
NSLog(@"--%d,%@,%@,%@,%@--/n",idx,obj.studentnumber,obj.name,obj.age,obj.gender);
}];
}
else
{
NSLog(@"error seach = %@",error);
}
return result;
}
-(IBAction)delete:(id)sender
{
NSArray * arr = [self searchResult];
__block Student * deletemp ;
[arr enumerateObjectsUsingBlock:^(Student * obj, NSUInteger idx, BOOL *stop) {
if ([obj.studentnumber intValue] == 2)
{
deletemp = obj;
*stop = YES;
}
}];
if (deletemp)
{
[[CoreDataManage GetManagedObjectContext] deleteObject:deletemp];
NSLog(@"====ok===delete");
}
}</span><span style="font-size:18px;">
</span>
現在編譯執行你的應用的話,表面上看起來應該都是一樣的,但是如果你看看控制檯的話,驚人的事情正在發生:
SELECT 0, t0.Z_PK FROM ZFAILEDBANKINFO t0 LEFT OUTER JOIN ZFAILEDBANKDETAILS t1 ON t0.ZDETAILS = t1.Z_PK ORDER BY t1.ZCLOSEDATE DESC total fetch execution time: 0.0033s for 234 rows. SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZSTATE, t0.ZCITY, t0.ZDETAILS FROM ZFAILEDBANKINFO t0 LEFT OUTER JOIN ZFAILEDBANKDETAILS t1 ON t0.ZDETAILS = t1.Z_PK WHERE t0.Z_PK IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ORDER BY t1.ZCLOSEDATE DESC LIMIT 20 total fetch execution time: 0.0022s for 20 rows. SELECT 0, t0.Z_PK, t0.Z_OPT, t0.ZNAME, t0.ZSTATE, t0.ZCITY, t0.ZDETAILS FROM ZFAILEDBANKINFO t0 LEFT OUTER JOIN ZFAILEDBANKDETAILS t1 ON t0.ZDETAILS = t1.Z_PK WHERE t0.Z_PK IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ORDER BY t1.ZCLOSEDATE DESC LIMIT 20 total fetch execution time: 0.0017s for 20 rows.
你可以看到, NSFetchedResultsController 正在從 FailedBankInfo中按照之前設定的順序取得大量的ID,根據UITableView的情況每次只緩衝一定數量的資料。比我們直接操控sqlite資料庫方便多了。