CoreData的構(gòu)成:
(1)NSManagedObjectContext 被管理者對(duì)象上下文,相當(dāng)于一個(gè)未存儲(chǔ)的臨時(shí)數(shù)據(jù)庫(kù),我們存儲(chǔ)或者查詢都是通過(guò)這個(gè)對(duì)象來(lái)的。
(2)NSManagedObjectModel 被管理對(duì)象模型,可以簡(jiǎn)單的理解為可視化建模文件,可視化建模中是Entity自動(dòng)生成model 方便讓文件存儲(chǔ)助理來(lái)進(jìn)行管理。
(3)NSPersistentStoreCoordinator 文件存儲(chǔ)助理,相當(dāng)于數(shù)據(jù)庫(kù)的鏈接器,它是CpreData的核心負(fù)責(zé)鏈接所有的模塊,包括真實(shí)的存儲(chǔ)文件。
(4)NSManagedObject 被管理的數(shù)據(jù)記錄, 相當(dāng)于數(shù)據(jù)庫(kù)中的表格記錄。
(5)NSFetchRequest 獲取數(shù)據(jù)的請(qǐng)求,相當(dāng)于SQL語(yǔ)句。
(6)NSEntityDescription 實(shí)體結(jié)構(gòu),相當(dāng)于表結(jié)構(gòu)。
(7)后綴為.xcdatamodeld的包 里面是.xcodemodel文件 用數(shù)據(jù)模型編輯器編譯。編譯后為.momd或.mom文件。
一些細(xì)節(jié):
1、NSManagedObjectContext創(chuàng)建時(shí)apple推薦使用參數(shù)NSPrivateQueueConcurrencyType或NSMainQueueConcurrencyType,二者區(qū)別如下:
使用NSMainQueueConcurrencyType初始化時(shí),block將會(huì)在主線程中執(zhí)行
[_context performBlock:^(){
[_context save:nil];
}];
使用NSPrivateQueueConcurrencyType初始化時(shí),block將會(huì)在新子線程中執(zhí)行,此中情況下涉及到更新UI的操作需要在主線程中調(diào)用,因此可以改進(jìn)如下:
[_context performBlock:^(){
[_context save:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[_tableView reloadData];
[self scrollToBottom];
});
}];
2、MOC不是線程安全的,多個(gè)線程不能使用同一個(gè),因此多線程使用MOC可以使用parent-child方法解決,每個(gè)子線程有一個(gè)MOC,主線程有一個(gè)MOC,主線程MOC是子線程MOC的parentContext。
例子如下:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
NSManagedObjectContext *childcontext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
childcontext.parentContext = _context;
[childcontext performBlock:^(){
Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:childcontext];
person.name = [NSString stringWithFormat:@"json%i",count++];
person.age = [NSNumber numberWithUnsignedInt:20];
person.timestamp = [NSDate date];
NSManagedObjectID *personid = person.objectID;
[childcontext save:nil];
[_context performBlock:^(){
[_context save:nil];
[_contextWrite performBlockAndWait:^(){
if ([_contextWrite hasChanges])
{
[_contextWrite save:nil];
}
}];
dispatch_async(dispatch_get_main_queue(), ^(){
[self.dataList addObject:[_contextWrite objectWithID:personid]];
[_tableView reloadData];
[self scrollToBottom];
});
}];
}];
});
以上parentcontext(main)<---childcontext(private)結(jié)構(gòu)就可以解決大多數(shù)問(wèn)題了,因?yàn)閿?shù)據(jù)庫(kù)的復(fù)雜操作往往來(lái)自于查詢,尤其那些正則匹配、模糊查找,而將這些費(fèi)時(shí)的操作放入childcontext中有多線程異步處理,可以不阻塞主線程。
上面的結(jié)構(gòu)相當(dāng)于將寫(xiě)入數(shù)據(jù)庫(kù)的操作放在主線程中執(zhí)行,因此對(duì)于大量寫(xiě)入數(shù)據(jù)庫(kù)的情況是不適用的。而此時(shí)則可以使用三層結(jié)構(gòu)解決:grandcontext(private)<---parentcontext(main)<---childcontext(private),其中childcontext負(fù)責(zé)數(shù)據(jù)處理查詢,parentcontext用于同步操作、解決線程安全問(wèn)題,grandcontext則用于寫(xiě)入操作。
3、多線程之間是不允許傳遞NSManagedObject的,但是可以通過(guò)傳遞NSManagedObjectID來(lái)解決。