Matching CoreData save notifications for callbacks - objective-c

I'd like to pick someone's brain on this. I have a dedicated save NSManagedObjectContext and GCD queue from which I operate on it. And whenever new data comes into my app I save it on that context and merge the changes into the main context. My problem arises in telling the main thread what just happened. Right after I call save my current context is now up-to-date, but if I fire a method in the main context it's context isn't. If I wait for the NSManagedObjectContextDidSave notification, and I save three times, I now have three queued delegate calls but no way to match them to the notifications coming in. Does anyone know of a good way to get around this?
EDIT
What I ended up doing was creating a new context for each save operation and attaching a block to be called when the save notification arrived. It looks like this, http://pastie.org/2068084

From your answer to my comment above, I see that you pass along the managedObjectContext in the notification. I'm not that confident about asynchronous stuff yet, but I do think that you're violating some concurrency rule, if I correctly interpret this quote from the NSManagedObjectContext Class Reference:
Concurrency
Core Data uses thread (or serialized queue) confinement to protect managed objects and managed object contexts (see “Concurrency with Core Data”). A consequence of this is that a context assumes the default owner is the thread or queue that allocated it—this is determined by the thread that calls its init method. You should not, therefore, initialize a context on one thread then pass it to a different thread. Instead, you should pass a reference to a persistent store coordinator and have the receiving thread/queue create a new context derived from that.
I'd say, try passing along the persistent store coordinator in the notification and recreate the managed object context in the block.

I'm not sure what you mean by, " ...if I fire a method in the main context it's context isn't. If I wait for the NSManagedObjectContextDidSave..." That implies that you are not waiting until the contexts have been merged. If so, that is why you can't access the data, it's just not in the front context.
Do you call mergeChangesFromContextDidSaveNotification: from the front context after it receives the notification?

Related

Refresh private queue when main queue changes in Core Data

I have two managed object contexts in my application, one of type NSMainQueueConcurrencyType, the other a temporary NSPrivateQueueConcurrencyType for background work.
I couldn't find the official solution to the following situation: When the private queue is doing some background work while the main queue deletes an object, I get an uncaught exception "Core Data could not fulfill a fault" when accessing this object in the background queue since it was deleted.
This is an expected behavior, however I am wondering how to handle these cases without getting a fault exception. I'm thinking this can be fixed by listening to the "NSManagedObjectContextDidSaveNotification" notification and then merging the background context with the main context but is this really the best way to do?
Yes, observe the did-save notification, and merge the changes with
[context mergeChangesFromContextDidSaveNotification:notification];
Also, you want to make sure you have setup an appropriate merge policy.

GPUImage gpus_ReturnNotPermittedKillClient crash using GPUImageFilter

I'm using GPUImageFilter in a chain, and most of the time it works OK. I've recently come across a few random crashes that match the symptoms in this github issue (albeit I'm using GPUImageFilter not live capture or video). I'm trying to find a suitable method that can ensure I've cleared the frame buffer and any other GPUImage-related activities in willResignActive.
Currently I have:
[[GPUImageContext sharedFramebufferCache] purgeAllUnassignedFramebuffers];
Is this sufficient? Should I use something else instead/in addition to?
As indicated there, seeing gpus_ReturnNotPermittedKillClient in a stack trace almost always is due to OpenGL ES operations being performed while your application is in the background or is just about to go to the background.
To deal with this, you need to guarantee that all GPUImage-related work is finished before your application heads to the background. You'll want to listen for delegate notifications that your application is heading to the background, and make sure all processing is complete before that delegate callback exits. The suggestion there by henryl is one way to ensure this. Add the following near the end of your delegate callback:
runSynchronouslyOnVideoProcessingQueue(^{
// Do some operation
});
What that will do is inject a synchronous block into the video processing pipeline (which runs on a background queue). Your delegate callback will block the main thread at that point until this block has a chance to execute, guaranteeing that all processing blocks before it have finished. That will make sure all pending operations are done (assuming you don't add new ones) before your application heads to the background.
There is a slight chance of this introducing a deadlock in your application, but I don't think any of my code in the processing pipeline calls back into the main queue. You might want to watch out for that, because if I do still have something in there that does that, this will lock your application. That internal code would need to be fixed if so.

Alternatives to dispatch_get_current_queue() for completion blocks in iOS 6?

I have a method that accepts a block and a completion block. The first block should run in the background, while the completion block should run in whatever queue the method was called.
For the latter I always used dispatch_get_current_queue(), but it seems like it's deprecated in iOS 6 or higher. What should I use instead?
The pattern of "run on whatever queue the caller was on" is appealing, but ultimately not a great idea. That queue could be a low priority queue, the main queue, or some other queue with odd properties.
My favorite approach to this is to say "the completion block runs on an implementation defined queue with these properties: x, y, z", and let the block dispatch to a particular queue if the caller wants more control than that. A typical set of properties to specify would be something like "serial, non-reentrant, and async with respect to any other application-visible queue".
** EDIT **
Catfish_Man put an example in the comments below, I'm just adding it to his answer.
- (void) aMethodWithCompletionBlock:(dispatch_block_t)completionHandler
{
dispatch_async(self.workQueue, ^{
[self doSomeWork];
dispatch_async(self.callbackQueue, completionHandler);
}
}
This is fundamentally the wrong approach for the API you are describing to take. If an API accepts a block and a completion block to run, the following facts need to be true:
The "block to run" should be run on an internal queue, e.g. a queue which is private to the API and hence entirely under that API's control. The only exception to this is if the API specifically declares that the block will be run on the main queue or one of the global concurrent queues.
The completion block should always be expressed as a tuple (queue, block) unless the same assumptions as for #1 hold true, e.g. the completion block will be run on a known global queue. The completion block should furthermore be dispatched async on the passed-in queue.
These are not just stylistic points, they're entirely necessary if your API is to be safe from deadlocks or other edge-case behavior that WILL otherwise hang you from the nearest tree someday. :-)
The other answers are great, but for the me the answer is structural. I have a method like this that's on a Singleton:
- (void) dispatchOnHighPriorityNonMainQueue:(simplest_block)block forceAsync:(BOOL)forceAsync {
if (forceAsync || [NSThread isMainThread])
dispatch_async_on_high_priority_queue(block);
else
block();
}
which has two dependencies, which are:
static void dispatch_async_on_high_priority_queue(dispatch_block_t block) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), block);
}
and
typedef void (^simplest_block)(void); // also could use dispatch_block_t
That way I centralize my calls to dispatch on the other thread.
You should be careful about your use of dispatch_get_current_queue in the first place. From the header file:
Recommended for debugging and logging purposes only:
The code
must not make any assumptions about the queue returned, unless it
is one of the global queues or a queue the code has itself created.
The code must not assume that synchronous execution onto a queue is
safe from deadlock if that queue is not the one returned by
dispatch_get_current_queue().
You could do either one of two things:
Keep a reference to the queue you originally posted on (if you created it via dispatch_queue_create), and use that from then on.
Use system defined queues via dispatch_get_global_queue, and keep a track of which one you're using.
Effectively whilst previously relying on the system to keep track of the queue you are on, you are going to have to do it yourself.
Apple had deprecated dispatch_get_current_queue(), but left a hole in another place, so we still able to get current dispatch queue:
if let currentDispatch = OperationQueue.current?.underlyingQueue {
print(currentDispatch)
// Do stuff
}
This works for main queue at least.
Note, that underlyingQueue property is available since iOS 8.
If you need to perform the completion block in the original queue, you also may use OperationQueue directly, I mean without GCD.
For those who still need in queue comparing, you could compare queues by their label or specifies.
Check this https://stackoverflow.com/a/23220741/1531141
This is a me too answer. So I will talk about our use case.
We have a services layer and the UI layer (among other layers). The services layer runs tasks in the background. (Data manipulation tasks, CoreData tasks, Network calls etc). The service layer has a couple operation queues to satisfy the needs of the UI layer.
The UI layer relies on the services layer to do its work and then run a success completion block. This block can have UIKit code in it. A simple use case is to get all messages from the server and reload the collection view.
Here we guarantee that the blocks that are passed into the services layer are dispatched on the queue on which the service was invoked on. Since dispatch_get_current_queue is a deprecated method, we use the NSOperationQueue.currentQueue to get the caller's current queue. Important note on this property.
Calling this method from outside the context of a running operation
typically results in nil being returned.
Since we always invoke our services on a known queue (Our custom queues and Main queue) this works well for us. We do have cases where serviceA can call serviceB which can call serviceC. Since we control where the first service call is being made from, we know the rest of the services will follow the same rules.
So NSOperationQueue.currentQueue will always return one of our Queues or the MainQueue.

Triggering via Asynchronous Callbacks

If an application executes a code block asynchronously and notifies the completion state in a callback, do these all leave execution on the main thread (the callback)?
What is the correct way to handle Core Graphics drawing and file operations in this callback?
I currently have these instructions running in the callback, but would like to trigger a thread to handle these instructions instead.
If you are doing any UI drawing, that has to be on the main thread. If you hvae these asynchronous blocks doing work now (ostensibly in a concurrent dispatch queue), why not just do all the work there, and when you have a finished product to show, only then message back on the main block. If your callback calls other methods in your class, the safest way to deal with concurrency is to define helper objects - small objects that take some input and product an output.
Create the helper, attach whatever data it needs, kick it off in a block on a queue, and when its done it messages back on the main thread that extracts the finished product, renders it, then deletes the helper object.
I dont have much experience in Core Graphics, but I've done a good amount of work on blocks.
In my opinion, if your application executes a code block asynchronously (on a new thread), then it's a good practice to the make callback or notification on the main thread.

CoreData Multithreading Proper Store Deletion

Ok, here's my situation:
I've got an app which requires a user-account.
While you're doing stuff like writing new comments, creating new Posts or reading a thread, every call to the server runs on a separate thread.
More specifically: A new thread is created, makes a call to the server, gets an answer from the server and saves the items from the answer to the Core Data Store.
In order to do this, every thread creates his own insertionContext, but they all share the same storeCoordinator.
But there's one Problem:
When someone does a logout from his account, I have to delete the store,
so if he logs in with another account, the stuff from the other account isn't in the coreDataStorage anymore.
But in Order to delete the Store, I have to make sure that there aren't any background Threads running anymore, because once they try to to save their stuff, they are sure to crash the app, since the store isn't valid anymore.
To clarify: these background threads are NSOperations which are put in an NSOperationQueue and executed from there.
Now CoreData gives the NSOperationQueue a function called "cancelAllOperations" but according to the Documentation, running Operations aren't killed, but only send a cancel message...
How do I use this cancel Message o_O
So far i'm checking at some points whether my thread is canceled and if it is, I don't execute other stuff, but if I do stuff like:
NSError *saveError = nil;
if(!self.isCanceled)
[insertionContext save:&saveError];
There is still the possibility that the Thread is being canceled between the if-check and the save.
So my question:
How do I handle this properly? Is it a question of properly canceling the thread?
I think you should not cancel any operations since it does not kill the thread immediately. Why don't you manage all operations that are currently being executed? This way you can postpone persistent store deletion until all tasks complete (or delete it immediately if there are no operations in progress).