• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: CoreData: Data freshness vs. multithreading
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

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
References: 
 >CoreData: Data freshness vs. multithreading (From: <email@hidden>)
 >Re: CoreData: Data freshness vs. multithreading (From: mmalcolm crawford <email@hidden>)
 >Re: CoreData: Data freshness vs. multithreading (From: Pierre Bernard <email@hidden>)
 >Re: CoreData: Data freshness vs. multithreading (From: Chris Hanson <email@hidden>)

  • Prev by Date: Re: NSOutlineView+NSTreeController+Drag&Drop
  • Next by Date: Re: Spotlight -- Metadata importer vs file package containing rtfd files
  • Previous by thread: Re: CoreData: Data freshness vs. multithreading
  • Next by thread: How to get the time and date format from user prefs
  • Index(es):
    • Date
    • Thread