2

I've got a button which marks a selected entry in a Core Data SQLite as a "Favourite", meaning I'm just flipping a BOOL for that index from off to on.

Currently, when I do this, I call save on the managedObjectContext, which takes maybe 500ms, perhaps a little more, according to Instruments.

I have some code that executes at the same time which triggers a nifty little particle explosion ("Hooray, a favourite!"), but I'm running into an issue where that explosion is delayed until after the save has completed.

I'm not sure why, since the code to trigger the explosion is before the save call. I'm a relatively new programmer so perhaps I'm missing something, but doesn't code execute line by line in a case like this, in that the explosion would trigger, then the save would occur while it's going? The delegate call here may be taking some time too, but the same question applies, why would it matter if it's after those lines of code?

EDIT: Am I right in saying that the main thread is being blocked before the particles appear by the next lines of code, meaning the UI can't update itself?

Here's my code:

// Particle animation LikeExplosion *likeExplosionView = [[LikeExplosion alloc] initWithFrame: CGRectMake(0, 0, 320, 400)]; [likeExplosionView setUserInteractionEnabled: NO]; [self.view addSubview: likeExplosionView]; [self.view bringSubviewToFront: likeExplosionView]; [likeExplosionView decayOverTime: 1.1]; // Delegate call to reload tableview elsewhere [self.delegate detailViewControllerDidLikeLine]; // Update current object [_selectedLine setIsLiked: [NSNumber numberWithBool: YES]]; [_selectedLine setIsDisliked: [NSNumber numberWithBool: NO]]; // Update context NSError *error; if (![[[CDManager sharedManager] managedObjectContext] save:&error]) NSLog(@"Saving changes failed: %@, %@", error, [error userInfo]); 

First question: why is there a delay, when I'm calling the animation code first in the method?

Second question: would putting the save call on a background thread solve the problem, and is it safe / a good idea to do so?

2
  • 1
    Probably you were on a background thread. Try to call your particle animation on main thread. Commented Apr 10, 2013 at 10:59
  • 1
    I've got no threading in the app at all at present, definitely not on a background thread. Commented Apr 10, 2013 at 11:02

3 Answers 3

11

Animations, and generally anything have to do with the UI is executed on the main thread. If you don't want the persistence to disk (the saving process) to hold up your UI (main thread) you need to put the context on it own private queue via NSManagedObjectContext's initWithConcurrencyType: method. The private queue will handle any background threads having to do with the context for you. The three types are:

NSConfinementConcurrencyType NSPrivateQueueConcurrencyType NSMainQueueConcurrencyType 

You would want NSPrivateQueueConcurrencyType.

You could take a more complex architecture route by using child/nested managed object contexts with different concurrency types, but if you are new to Core Data, stick with a single context until you get a firm grasp of contexts and queues.

Sign up to request clarification or add additional context in comments.

3 Comments

So when I first create the NSManagedObjectContext (which only happens once, at the very first launch of the app) I'd initialize it with that type, then every time it's used elsewhere, it'll use a background thread (or PrivateQueue)?
Yes it would use it's own queue, therefore not block UI and handling any off-shot threads internally.
Also, make sure you use the context's performBlock: or `performBlockAndWait:' on your save method. This will ensure thread safety with your context.
8

1) your animation will not start running until the main runloop complete its cycle. this cycle will not complete as save: is a blocking method.

2) Moving your save to a background thread will solve the issue, but you must access the main managedObjectContext in the main thread, so, you either have to use a background context:

NSManagedObjectContext* context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mergeChanges:) name:NSManagedObjectContextDidSaveNotification object:context]; [context performBlock:^{ //make changes NSError* error = nil; [context save:&error]; //remember to remove observer after the save (in mergeChanges: and dealloc) }]; 

You might be able to start the animation without moving to background by scheduling the save on the main thread in the next runloop using: [self performSelectorOnMainThread:@selector(saveMain) withObject:nil waitUntilDone:NO];

Comments

3

Check out this great article on CIMGF.com! ;)

After reading the tutorial you should know how to approach this problem.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.