Re: CoreData: Data freshness vs. multithreading
Re: CoreData: Data freshness vs. multithreading
- Subject: Re: CoreData: Data freshness vs. multithreading
- From: Pierre Bernard <email@hidden>
- Date: Tue, 3 May 2005 22:14:55 +0200
Hi!
Here is what I came up with to keep the main threads context in sync
with the other threads' contexts. I use NSPorts to get the handling
of the notification back into the main thread.
- (NSManagedObjectContext *) managedObjectContext
{
if (!managedObjectContext)
{
// SNIP ...
port = [[NSPort alloc] init];
[[NSRunLoop currentRunLoop] addPort:port
forMode:NSDefaultRunLoopMode];
[port setDelegate:self];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector
(managedObjectContextDidSaveNotification:)
name:NSManagedObjectContextDidSaveNotification
object:nil];
}
return managedObjectContext;
}
- (void) managedObjectContextDidSaveNotification:(NSNotification*)
notification
{
NSManagedObjectContext* objectContext =
(NSManagedObjectContext*) [notification object];
if (objectContext != [self managedObjectContext])
{
NSDictionary* userInfo = [notification userInfo];
NSMutableSet* objects = [[NSMutableSet alloc] init];
[objects unionSet:[userInfo
objectForKey:NSInsertedObjectsKey]];
[objects unionSet:[userInfo objectForKey:NSUpdatedObjectsKey]];
[objects unionSet:[userInfo objectForKey:NSDeletedObjectsKey]];
NSEnumerator* enumerator = [objects objectEnumerator];
NSMutableSet* objectIDs = [[NSMutableSet alloc]
initWithCapacity:[objects count]];
NSManagedObject* managedObject = nil;
while (managedObject = (NSManagedObject*) [enumerator
nextObject])
{
[objectIDs addObject:[managedObject objectID]];
}
NSData* data = [[NSData alloc] initWithBytes:&objectIDs
length:sizeof(void *)];
NSArray* components = [[NSArray alloc]
initWithObjects:data,nil];
NSPortMessage* message = [[NSPortMessage alloc]
initWithSendPort:port
receivePort:nil
components:components];
[message sendBeforeDate:[NSDate date]];
[objects release];
[data release];
[components release];
[message release];
}
}
- (void) handlePortMessage:(NSPortMessage*)portMessage
{
NSArray* components = [portMessage components];
NSData* data = (NSData*) [components objectAtIndex:0];
NSMutableSet* objectIDs = *((NSMutableSet**) [data bytes]);
NSManagedObjectContext* objectContext = [self
managedObjectContext];
NSEnumerator* enumerator = [objectIDs objectEnumerator];
NSManagedObjectID* objectID = nil;
while (objectID = (NSManagedObjectID*) [enumerator nextObject])
{
NSManagedObject* managedObject = [objectContext
objectRegisteredForID:objectID];
if (managedObject)
{
[objectContext refreshObject:managedObject
mergeChanges:YES];
}
}
[objectIDs release];
}
Please be indulgent. This is my first go at Cocoa.
Pierre
On May 3, 2005, at 9:21 PM, Chris Hanson wrote:
On May 3, 2005, at 11:15 AM, Pierre Bernard wrote:
BTW, what's the word on locking NSManagedObjectContext in a
multithreaded environment? Same policy as for EOEditingContext?
It's not the same as EOF.
The recommendation is to avoid using the same managed object
context or managed object in more than one thread. Instead, keep
contexts and their associated object graphs separated on a per-
thread basis, and pass object IDs between them using the thread's
context's -objectWithID: to instantiate the object. And note that
any time you manipulate or access your object graph, you may be
using the associated managed object context.
This is not a situation where reads are "safe" but changes are
"dangerous" -- every operation is "dangerous" because every
operation can trigger faulting. If you only pass object IDs across
thread boundaries you're isolated from this and don't have to worry
about it, but if you try to pass actual objects around, share
contexts between threads, etc. you'll need to be *extremely*
careful about locking.
If you're sharing a managed object context or a persistent store
coordinator between threads, and you invoke any methods on it, you
need to ensure that they are invoked from a thread-safe scope (e.g.
you've locked the context or coordinator via its -tryLock/-lock
methods). If you do this, the framework will ensure that what it
does behind the scenes is also thread-safe.
Your best bet, especially for end-user Cocoa applications, is to:
(1) Have one persistent store coordinator per group of cooperating
threads, e.g. for your application or for each document.
(2) Give each thread its own entirely private managed object context.
(3) Never pass managed object contexts or managed objects between
threads.
(4) Pass managed object IDs between threads and use -objectWithID:
on the thread's local managed object context to get a local version
of a managed object.
-- Chris
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Cocoa-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden