多线程操作数据库 (CoreData)
2013-10-21 10:49
357 查看
1: 主线程修改了数据库的某一条记录,但是子线程没有发生变化,反过来一样的问题。这种情况一般是发生在app有多个NSManagedObjectContext,两个线程分别对其进行了读写操作。
2: 有时候程序会莫名其妙的crash掉,这个有很多原因:
a: 有时候是因为两个线程同时读写数据库中的同一条记录。
b: 有时候根本找不到是哪里的原因。
这两种情况一般是发生在app只有一个NSManagedObjectContext,两个线程都对其进行了读写操作。
在实际的开发当中,我遇到了各种各样的问题,如果是多线程操作数据库的话,个人建议:
1: 最好一个线程对应一个NSManagedObjectContext。如果只有一个NSManagedObjectContext,并且多个线程对其进行操作,回出现许多不清不楚的问题。
2:在每一个线程对应一个NSManagedObjectContext的时候,尽量一个线程只读写与其对应的context。在其完成操作的时候通知另外的线程去修改其对应的context。在apple的api中有NSManagedObjectContextDidSaveNotification, 它可以帮助你通知修改其它的contexts。
eg: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:childThreadManagedObjectContext];
- (NSManagedObjectContext*)childThreadContext
{
if (childThreadManagedObjectContext != nil)
{
return childThreadManagedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
childThreadManagedObjectContext = [[NSManagedObjectContext alloc] init];
[childThreadManagedObjectContext setPersistentStoreCoordinator:coordinator];
}
else
{
DLog(@"create child thread managed object context failed!");
}
[childThreadManagedObjectContext setStalenessInterval:0.0];
[childThreadManagedObjectContext setMergePolicy:NSOverwriteMergePolicy];
//////init entity description.
pChildThreadEntityDec = [NSEntityDescription entityForName:@"student" inManagedObjectContext:childThreadManagedObjectContext];
if (pChildThreadEntityDec == nil)
{
DLog(@"error init entity description!");
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:childThreadManagedObjectContext];
return childThreadManagedObjectContext;
}
- (void)mergeOnMainThread:(NSNotification *)aNotification
{
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:aNotification];
}
- (void)mergeContextChangesForNotification:(NSNotification *)aNotification
{
[self performSelectorOnMainThread:@selector(mergeOnMainThread:) withObject:aNotification waitUntilDone:YES];
}
上面的代码只是简单利用NSManagedObjectContextDidSaveNotification,当子线程修改了数据库以后,通知主线程去修改其对应的context。当然childThreadManagedObjectContext的创建是在创建子线程的时候进行的。
- (void)startChildThread
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
if ([[manageDatabase sharedInstance] childThreadContext] == nil)
{
DLog(@"create child thread context failed.");
}
[NSTimer scheduledTimerWithTimeInterval:10000.0 target:self selector:@selector(printCurrentData) userInfo:nil repeats: YES];
[runLoop run];
[pool release];
}
注:实际上在什么时候创建都可以,只要保证在第一次用的之前创建好就可以了。上面是childThreadManagedObjectContext发生改变时,通知主context修改,所以在修改数据库时,一般都是修改childThreadManagedObjectContext。
eg:
- (void)saveDatabase:(student*)inObject withAge:(NSNumber *)inAge
{
if (inObject==nil || inAge==nil)
{
return;
}
NSError* pError;
if (self.age != nil)
{
[self.age release];
self.age = nil;
}
self.age = [[NSNumber alloc] initWithInt:[inAge intValue]];
if ([NSThread currentThread] == [NSThread mainThread])
{
[self performSelector:@selector(saveWithChildThread:) onThread:[dataBaseAppDelegate shareDelegate].viewController.pShowController.pChildThread withObject:inObject waitUntilDone:NO];
}
else
{
inObject.stuAge = inAge;
if (![childThreadManagedObjectContext save:&pError])
{
NSLog(@"save failed: %@, %@", pError, [pError userInfo]);
}
}
}
- (void)saveWithChildThread:(student*)inStudent
{
NSError* pError;
NSManagedObjectID* tempObjectID = [inStudent objectID];
student* tempStudet = (student*)[childThreadManagedObjectContext objectWithID:tempObjectID];
tempStudet.stuAge = age;
if (![childThreadManagedObjectContext save:&pError])
{
NSLog(@"save failed: %@, %@", pError, [pError userInfo]);
}
}
这里修改数据库都是通过saveWithChildThread去修改的。当然上面 if ([NSThread currentThread] == [NSThread mainThread]),如果时在主线程也可以直接调用saveWithChildThread,而不用放到子线程修改,这里只是为了统一。每个context只在其对应的线程中修改。
原文地址:http://linwwwei.iteye.com/blog/1296559
2: 有时候程序会莫名其妙的crash掉,这个有很多原因:
a: 有时候是因为两个线程同时读写数据库中的同一条记录。
b: 有时候根本找不到是哪里的原因。
这两种情况一般是发生在app只有一个NSManagedObjectContext,两个线程都对其进行了读写操作。
在实际的开发当中,我遇到了各种各样的问题,如果是多线程操作数据库的话,个人建议:
1: 最好一个线程对应一个NSManagedObjectContext。如果只有一个NSManagedObjectContext,并且多个线程对其进行操作,回出现许多不清不楚的问题。
2:在每一个线程对应一个NSManagedObjectContext的时候,尽量一个线程只读写与其对应的context。在其完成操作的时候通知另外的线程去修改其对应的context。在apple的api中有NSManagedObjectContextDidSaveNotification, 它可以帮助你通知修改其它的contexts。
eg: [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:childThreadManagedObjectContext];
- (NSManagedObjectContext*)childThreadContext
{
if (childThreadManagedObjectContext != nil)
{
return childThreadManagedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
childThreadManagedObjectContext = [[NSManagedObjectContext alloc] init];
[childThreadManagedObjectContext setPersistentStoreCoordinator:coordinator];
}
else
{
DLog(@"create child thread managed object context failed!");
}
[childThreadManagedObjectContext setStalenessInterval:0.0];
[childThreadManagedObjectContext setMergePolicy:NSOverwriteMergePolicy];
//////init entity description.
pChildThreadEntityDec = [NSEntityDescription entityForName:@"student" inManagedObjectContext:childThreadManagedObjectContext];
if (pChildThreadEntityDec == nil)
{
DLog(@"error init entity description!");
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeContextChangesForNotification:) name:NSManagedObjectContextDidSaveNotification object:childThreadManagedObjectContext];
return childThreadManagedObjectContext;
}
- (void)mergeOnMainThread:(NSNotification *)aNotification
{
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:aNotification];
}
- (void)mergeContextChangesForNotification:(NSNotification *)aNotification
{
[self performSelectorOnMainThread:@selector(mergeOnMainThread:) withObject:aNotification waitUntilDone:YES];
}
上面的代码只是简单利用NSManagedObjectContextDidSaveNotification,当子线程修改了数据库以后,通知主线程去修改其对应的context。当然childThreadManagedObjectContext的创建是在创建子线程的时候进行的。
- (void)startChildThread
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
if ([[manageDatabase sharedInstance] childThreadContext] == nil)
{
DLog(@"create child thread context failed.");
}
[NSTimer scheduledTimerWithTimeInterval:10000.0 target:self selector:@selector(printCurrentData) userInfo:nil repeats: YES];
[runLoop run];
[pool release];
}
注:实际上在什么时候创建都可以,只要保证在第一次用的之前创建好就可以了。上面是childThreadManagedObjectContext发生改变时,通知主context修改,所以在修改数据库时,一般都是修改childThreadManagedObjectContext。
eg:
- (void)saveDatabase:(student*)inObject withAge:(NSNumber *)inAge
{
if (inObject==nil || inAge==nil)
{
return;
}
NSError* pError;
if (self.age != nil)
{
[self.age release];
self.age = nil;
}
self.age = [[NSNumber alloc] initWithInt:[inAge intValue]];
if ([NSThread currentThread] == [NSThread mainThread])
{
[self performSelector:@selector(saveWithChildThread:) onThread:[dataBaseAppDelegate shareDelegate].viewController.pShowController.pChildThread withObject:inObject waitUntilDone:NO];
}
else
{
inObject.stuAge = inAge;
if (![childThreadManagedObjectContext save:&pError])
{
NSLog(@"save failed: %@, %@", pError, [pError userInfo]);
}
}
}
- (void)saveWithChildThread:(student*)inStudent
{
NSError* pError;
NSManagedObjectID* tempObjectID = [inStudent objectID];
student* tempStudet = (student*)[childThreadManagedObjectContext objectWithID:tempObjectID];
tempStudet.stuAge = age;
if (![childThreadManagedObjectContext save:&pError])
{
NSLog(@"save failed: %@, %@", pError, [pError userInfo]);
}
}
这里修改数据库都是通过saveWithChildThread去修改的。当然上面 if ([NSThread currentThread] == [NSThread mainThread]),如果时在主线程也可以直接调用saveWithChildThread,而不用放到子线程修改,这里只是为了统一。每个context只在其对应的线程中修改。
原文地址:http://linwwwei.iteye.com/blog/1296559
相关文章推荐
- 多线程操作数据库 (CoreData)
- 多线程操作数据库 (CoreData)
- 多线程操作数据库 (CoreData)
- [Swift 开发] swift支持多线程操作数据库类库-CoreDataManager
- 多线程操作数据库 (CoreData)
- CoreData的简单使用<二、CoreData两张数据库表的关联操作>
- 多线程下,多次操作数据库报错,There is already an open DataReader associated with this Command which must be closed first.
- Core Data 多线程操作实战篇
- swift支持多线程操作数据库类库-CoreDataManager
- IOS coredata数据库操作
- 面向对象方式使用数据库---CoreData的基本使用
- 认识CoreData—多线程
- coredata 查询操作的核心代码
- ASP.NET4.0 Ajax实例 –Javascript调用 ADO.NET Data Service实现数据库操作
- Python 数据处理扩展包: pandas 模块的DataFrame介绍(读写数据库的操作)
- iOS core Data 详解-<2>多线程
- 多线程使用ADO操作数据库时,CreateInstance对象回失败
- 数据库操作(fmdb多线程操作)
- CoreData数据库搭建
- Qt 多线程与数据库操作需要注意的几点问题(QSqlDatabase对象只能在当前线程里使用)