NSEntityDescription是實體描述對象,它可以類比如資料庫中的表,NSEntityDescription存放的是表的結構資訊。這些類都是一些抽象的結構類,並不儲存實際每條資料的資訊,具體的資料由NSManagedObject類來描述,我們一般會將實體類化繼承於NSManagedObject。
Xocde工具提供了快捷的實體類化功能,還拿我們一開始建立的班級與學生實體來示範,點擊.xcdatamodeld檔案,點擊Xcode工具上方導覽列的Editor標籤,選擇Creat NSManagedObject Subclass選項,在彈出的視窗中勾選要類化的實體,如下圖:
這時,Xcode會自動為我們建立一個檔案,這些檔案中有各個類中屬性的聲明。
一、建立一條資料
使用如下代碼進行資料的建立:
//讀取資料模型檔案
NSURL *modelUrl = [[NSBundle mainBundle]URLForResource:@"Model" withExtension:@"momd"];
//建立資料模型
NSManagedObjectModel * mom = [[NSManagedObjectModel alloc]initWithContentsOfURL:modelUrl];
//建立持久化儲存協調者
NSPersistentStoreCoordinator * psc = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:mom];
//資料庫儲存路徑
NSURL * path =[NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"CoreDataExample.sqlite"]];
//為持久化協調者添加一個資料接收棧
/*
可以支援的類型如下:
NSString * const NSSQLiteStoreType;//sqlite
NSString * const NSXMLStoreType;//XML
NSString * const NSBinaryStoreType;//二進位
NSString * const NSInMemoryStoreType;//記憶體
*/
[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:path options:nil error:nil];
//建立資料管理上下文
NSManagedObjectContext * moc = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSMainQueueConcurrencyType];
//關聯持久化協調者
[moc setPersistentStoreCoordinator:psc];
//建立資料對象
/*
資料對象的建立是通過實體名擷取到的
*/
SchoolClass * modelS = [NSEntityDescription insertNewObjectForEntityForName:@"SchoolClass" inManagedObjectContext:moc];
//對資料進行設定
modelS.name = @"第一班";
modelS.stuNum = @60;
//進行儲存
if ([moc save:nil]) {
NSLog(@"新增成功");
}
NSLog(@"%@",[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"CoreDataExample.sqlite"]);
找到在列印出的路徑,會發現裡面多了一個sqlite檔案,其中有一張表中添加進了一條資料。
二、查詢資料
CoreData中通過查詢請求來對資料進行查詢操作,查詢請求由NSFetchRequest來進行管理和維護。
NSFetchRequest主要提供兩個方面的查詢服務:
1.提供範圍查詢的相關功能
2.提供查詢結果傳回型別與排序的相關功能
NSFetchRequest中常用方法如下:
//建立一個實體的查詢請求 可以理解為在某個表中進行查詢
+ (instancetype)fetchRequestWithEntityName:(NSString*)entityName;
//查詢條件
@property (nullable, nonatomic, strong) NSPredicate *predicate;
//資料排序
@property (nullable, nonatomic, strong) NSArray<NSSortDescriptor *> *sortDescriptors;
//每次查詢返回的資料條數
@property (nonatomic) NSUInteger fetchLimit;
//設定查詢到資料的傳回型別
/*
typedef NS_OPTIONS(NSUInteger, NSFetchRequestResultType) {
NSManagedObjectResultType = 0x00,
NSManagedObjectIDResultType = 0x01,
NSDictionaryResultType NS_ENUM_AVAILABLE(10_6,3_0) = 0x02,
NSCountResultType NS_ENUM_AVAILABLE(10_6,3_0) = 0x04
};
*/
@property (nonatomic) NSFetchRequestResultType resultType;
//設定查詢結果是否包含子實體
@property (nonatomic) BOOL includesSubentities;
//設定要查詢的屬性值
@property (nullable, nonatomic, copy) NSArray *propertiesToFetch;
在SchoolClass實體中查詢資料,使用如下的代碼:
//建立一條查詢請求
NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"SchoolClass"];
//設定條件為 stuNum=60的資料
[request setPredicate:[NSPredicate predicateWithFormat:@"stuNum == 60"]];
//進行查詢操作
NSArray * res = [moc executeFetchRequest:request error:nil];
NSLog(@"%@",[res.firstObject stuNum]);
進行資料初始化
NSFetchedResultsController的初始化需要一個查詢請求和一個資料操作上下文。程式碼範例如下:
//遵守協議
@interface ViewController ()<NSFetchedResultsControllerDelegate>
{
//資料橋接對象
NSFetchedResultsController * _fecCon;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//進行初始化操作
NSURL *modelUrl = [[NSBundle mainBundle]URLForResource:@"Model" withExtension:@"momd"];
NSManagedObjectModel * mom = [[NSManagedObjectModel alloc]initWithContentsOfURL:modelUrl];
NSPersistentStoreCoordinator * psc = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:mom];
NSURL * path =[NSURL fileURLWithPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"CoreDataExample.sqlite"]];
[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:path options:nil error:nil];
NSManagedObjectContext * moc = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc setPersistentStoreCoordinator:psc];
NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:@"SchoolClass"];
//設定資料排序
[request setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"stuNum" ascending:YES]]];
//進行資料橋接對象的初始化
_fecCon = [[NSFetchedResultsController alloc]initWithFetchRequest:request managedObjectContext:moc sectionNameKeyPath:nil cacheName:nil];
//設定代理
_fecCon.delegate=self;
//進行資料查詢
[_fecCon performFetch:nil];
}
@end
用於初始化NSFecthedResultsController的資料請求對象必須設定一個定序。在initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName:方法中,如果設定第三個參數,則會以第三個參數為索引值進行資料的分區。當資料發生變化時,將通過代理進行方法的回調。
三、與UITableView進行資料繫結
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"cellid"];
if (!cell) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"cellid"];
}
//擷取相應資料模型
SchoolClass * obj = [_fecCon objectAtIndexPath:indexPath];
cell.textLabel.text = obj.name;
cell.detailTextLabel.text = [NSString stringWithFormat:@"有%@人",obj.stuNum];
return cell;
}
-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return [_fecCon sections].count;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
id<NSFetchedResultsSectionInfo> info = [_fecCon sections][section];
return [info numberOfObjects];
}
效果如下:
四、將資料變化映射到視圖
//資料將要改變時調用的方法
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
//開啟tableView更新預先處理
[[self tableView] beginUpdates];
}
//分區資料改變時調用的方法
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
{
//判斷行為類型
switch(type) {
//插入新分區
case NSFetchedResultsChangeInsert:
[[self tableView] insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
//刪除分區
case NSFetchedResultsChangeDelete:
[[self tableView] deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
break;
//移動分區
case NSFetchedResultsChangeMove:
//更新分區
case NSFetchedResultsChangeUpdate:
break;
}
}
//資料改變時回調的代理
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
{
switch(type) {
//插入資料
case NSFetchedResultsChangeInsert:
[[self tableView] insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
//刪除資料
case NSFetchedResultsChangeDelete:
[[self tableView] deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
//更新資料
case NSFetchedResultsChangeUpdate:
[self reloadData];
break;
//移動資料
case NSFetchedResultsChangeMove:
[[self tableView] deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[[self tableView] insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
//資料更新結束調用的代理
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[[self tableView] endUpdates];
}