iOS程式碼重構(二)CoreData多執行緒(支援執行緒安全)
CoreData對多執行緒的支援比較奇怪(按照一般的思路來說),CoreData的NSPersistentStoreCoordinator和NSManagedObjectContext物件都是不能跨執行緒使用的,NSManagedObject也不行,有人想加鎖不就完了。
前提描述
原專案中已有CoreData封裝,但是執行緒不完全的,而且應用的地方較多,參考了網上的一些文章,如果按主流的搞個三層上下文saveMOC,mainMOC,newPrivateMOC,應用Block來實現非同步。但專案改動較大。而且經測試,程式碼健壯性不是很好,多執行緒操作時,
有崩潰現象。原專案中的資料庫檔案,是按使用者,分別建立的。
基本方案:應用MagicRecord部分API,實現Core執行緒安全, 改動控制在CoreDataManager內。
MagicRecord實現的是三層結構,
[NSManagedObjectContextMR_rootSavingContext] 根MOC
[NSManagedObjectContextMR_defaultContext] 對應MainMOC,主MOC,它的父是rootSavingContext
[NSManagedObjectContextMR_context] 對應privateMoc,私有MOC,它的父是defualtContext,每次呼叫都會新建立一個MOC
直接上程式碼吧
1 初始化操作
AppDelegate.m
NSString *userId = [[PublicObjectpublicObjectInstance] getUserId];
if (userId) {//登入後再初始化本地資料庫
[[CoreDataManagershareInstance] setupCoreDataStack];
[MagicalRecordsetLoggingLevel:MagicalRecordLoggingLevelAll];
}
2 CoreDataManager部分函式
- (void) setupCoreDataStack
{
if ([NSPersistentStoreCoordinatorMR_defaultStoreCoordinator] !=nil) return;
NSPersistentStoreCoordinator *coordinator = [selfpersistentStoreCoordinator];
[NSPersistentStoreCoordinatorMR_setDefaultStoreCoordinator:coordinator];
[NSManagedObjectContextMR_initializeDefaultContextWithCoordinator:coordinator];
}
// Returns the managed object model for the application.
// If the model doesn't already exist, it is created from the application's model.
- (NSManagedObjectModel *)managedObjectModel {
if (!_managedObjectModel) {
NSURL *modelURL = [[NSBundlemainBundle] URLForResource:@"ModelObject"withExtension:@"momd"];
_managedObjectModel = [[NSManagedObjectModelalloc] initWithContentsOfURL:modelURL];
}
return_managedObjectModel;
}
// Returns the persistent store coordinator for the application.
// If the coordinator doesn't already exist, it is created and the application's store added to it.
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (!_persistentStoreCoordinator) {
NSURL* storeURL = [NSURLfileURLWithPath:[FileHelperinfodbFilePath]];//Lib目錄/使用者ID/info.db
NSError *error =nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinatoralloc] initWithManagedObjectModel:[selfmanagedObjectModel]];
NSDictionary *options =@{NSMigratePersistentStoresAutomaticallyOption : [NSNumbernumberWithBool:YES],
NSInferMappingModelAutomaticallyOption : [NSNumbernumberWithBool:YES]};
if (![_persistentStoreCoordinatoraddPersistentStoreWithType:NSSQLiteStoreTypeconfiguration:nilURL:storeURL options:optionserror:&error]) {
NSLog(@"Unresolved error %@, %@", error, [erroruserInfo]);
abort();
}
}
return_persistentStoreCoordinator;
}
-(BOOL) save:(NSError **)error{
[[NSManagedObjectContextMR_defaultContext] MR_saveToPersistentStoreAndWait];
returnYES;
}
- (void)removeObjectsWithPredicate:(NSPredicate*)predicate inEntity:(NSString*)entityName {
NSManagedObjectContext *context = [NSManagedObjectContextMR_context];
NSFetchRequest *request = [[NSFetchRequestalloc] init];
request.predicate = predicate;
request.includesPropertyValues =NO;
request.entity = [NSEntityDescriptionentityForName:entityNameinManagedObjectContext:context];
[context performBlockAndWait:^{
NSError *error;
NSArray *objects = [contextexecuteFetchRequest:requesterror:&error];
if (!error && objects.count) {
for (NSManagedObject *objin objects) {
[context deleteObject:obj];
}
}
}];
[context MR_saveToPersistentStoreAndWait];
}
- (NSMutableArray*)findObjectsIn:(NSString*)entityName withPredicate:(NSPredicate*)predicate andSortDescriptors:(NSArray*)sortDescriptors andObjectClass:(Class)objClass {
NSManagedObjectContext *context = [NSManagedObjectContextMR_context];
NSFetchRequest *request = [[NSFetchRequestalloc] init];
request.predicate = predicate;
request.sortDescriptors = sortDescriptors;
request.entity = [NSEntityDescriptionentityForName:entityNameinManagedObjectContext:context];
__blockNSMutableArray *results =nil;
[context performBlockAndWait:^{
NSError *error =nil;
NSArray *objects = [contextexecuteFetchRequest:requesterror:&error];
if (objects ==nil)
{
NSLog(@"%@",error);
return ;
}
results = [NSMutableArrayarrayWithCapacity:objects.count];
if (!error && objects.count) {
for (id entityin objects) {
id obj = [[objClassalloc] initWithEntity:entity];
[results addObject:obj];
}
}
}];
return results;
}
//插入- (void)insertProgressAndAttachments:(NSArray *)progressArray
{
NSManagedObjectContext *context = [NSManagedObjectContextMR_context];
for (Progress *progressin progressArray) {
Progress* entity = (Progress*)[NSEntityDescriptioninsertNewObjectForEntityForName:TBProgress
inManagedObjectContext:context];
entity.projectId = progress.projectId;
entity.buildingId = progress.buildingId;
entity.progressId = progress.progressId;
entity.createdDate = progress.createdDate;
entity.createdBy = progress.createdBy;
entity.lastModifiedDate = progress.lastModifiedDate;
entity.lastModifiedBy = progress.lastModifiedBy;
entity.occurredDate = progress.occurredDate;
entity.progressDesc = progress.progressDesc;
entity.version = progress.version;
entity.progressStatus = progress.progressStatus;
entity.conflict = progress.conflict;
entity.weather = progress.weather;
entity.temperature = progress.temperature;
entity.windPower = progress.windPower;
for (ProgressAttachment *attachin progress.attachments) {
[selfinsertProgressAttachment:attach];
}
for (ProgressWorkType *workTypein progress.workTypes) {
[selfinsertProgressWorkType:workType];
}
for (ProgressDelayReason *delayReasonin progress.delayReasons) {
[selfinsertProgressDelayReason:delayReason];
}
}
[context MR_saveToPersistentStoreAndWait];
}
//查詢
- (Progress*)findProgressById:(NSString *)progressId {
return [selffindFirstObjectIn:TBProgress
withPredicate:[NSPredicatepredicateWithFormat:@"progressId = %@", progressId]
andSortDescriptors:nil
andObjectClass:[Progressclass]];
}
//刪除
// 刪除一個專案的所有進度附件
- (void)removeAllProgressAttachmentByProject:(NSString*)projectId {
[selfremoveObjectsWithPredicate:[NSPredicatepredicateWithFormat:@"projectId = %@", projectId]
inEntity:TBProgressAttachment];
}
參考文章:
原始碼
原理-知識
認識CoreData—多執行緒
iOS開發中一些常見的並行處理
對應Demo
在多執行緒環境中使用CoreData
英文版
不再替Core Data多執行緒程式設計而頭疼
Magical Record 全面解析
MagicalRecord初始化,資料遷移與提前預製資料庫邏輯