您的位置:首页 > 移动开发 > IOS开发

coreData 深入理解3 (iOS5 以前线程安全与同步)

2014-03-24 15:20 253 查看
iOS5 以前采用方法:

1: 主线程修改了数据库的某一条记录,但是子线程没有发生变化,反过来一样的问题。这种情况一般是发生在app有多个NSManagedObjectContext,两个线程分别对其进行了读写操作。

2: 有时候程序会莫名其妙的crash掉,这个有很多原因:

a: 有时候是因为两个线程同时读写数据库中的同一条记录。

b: 在Core Data的多线程环境中,我们只能传递objectID或者重新fetch, 而我们传递了object

c: 有时候根本找不到是哪里的原因。

这两种情况一般是发生在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;

// 传递objectID !!!

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只在其对应的线程中修改。

(iOS5 以后iOS 对此引入parent context conception, 就可用不用注册通知了,参加coreData 深入理解2)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: