CoreData对多线程的支持比较奇怪(按照一般的思路来说),CoreData的NSPersistentStoreCoordinator和NSManagedObjectContext对象都是不能跨线程使用的,NSManagedObject也不行,有人想加锁不就完了。
前提描述
原项目中已有CoreData封装,但是线程不完全的,而且应用的地方较多,参考了网上的一些文章,如果按主流的搞个三层上下文saveMOC,mainMOC,newPrivateMOC,应用Block来实现异步。但项目改动较大。而且经测试,代码健壮性不是很好,多线程操作时,
有崩溃现象。原项目中的数据库文件,是按用户,分别创建的。
基本方案:应用MagicRecord部分API,实现Core线程安全, 改动控制在CoreDataManager内。
MagicRecord实现的是三层结构,
[NSManagedObjectContext MR_rootSavingContext] 根MOC
[NSManagedObjectContext MR_defaultContext] 对应MainMOC,主MOC,它的父是rootSavingContext
[NSManagedObjectContext MR_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];
}
参考文章:
源码
https://github.com/search?utf8=✓&q=iOS+coredata+thread
原理-知识
认识CoreData—多线程
http://www.tuicool.com/articles/2iimue
iOS开发中一些常见的并行处理
http://www.cocoachina.com/industry/20131212/7525.html
对应Demo
https://github.com/Acorld/IOS_CoreData_MutThread_Demo
在多线程环境中使用CoreData
http://www.iliunian.com/2896.html
英文版
https://www.cocoanetics.com/2012/07/multi-context-coredata/
不再替Core Data多线程编程而头疼
http://www.myexception.cn/program/1937577.html
Magical Record 全面解析
http://www.jianshu.com/p/590c6db9cdd6
MagicalRecord初始化,数据迁移与提前预制数据库逻辑
http://www.jianshu.com/p/cd1a06c7ce09