Is it safe to use managed objects loaded in background by performBlock: in main thread? - objective-c

I'm creating my managed object context with NSPrivateQueueConcurrencyType concurrency type.
Also I'm using performBlock: selector to execute operations in background. So If I'm fetching some objects in background (in performBlock:), is it safe to use resulting managed objects in main thread?

As a general rule, no it is not safe to share NSManagedObject instances across threads no matter what concurrency type you are using.
However there is a library you can use to make your context(s) and object instances thread-safe. With that you can pretty much ignore all the nonsense about ensuring thread isolation between contexts and focus your efforts on the things that matter, like building out the actual functionality of your app.

I'm not 100% sure, but in my own experience I do it this way: If you are changing the variables properties, do it inside performBlock. I had one case where reading was causing some weird behavior, but in general it seems to be OK. If you want to be extra safe, use performBlock every time you touch a managed object in any way.

You will need to use a different context for each thread as explained here iOS Developer - Core data multithreading
One way to implement is described at Core Data - one context per thread implementation

Sorry, I should've search better, here is exactly my question & answer to it:
Core Data's NSPrivateQueueConcurrencyType and sharing objects between threads

Related

Does accessing a property on an NSManagedObject from a background thread make the context cross that thread?

I need to use a property on my NSManagedObjectContext as a parameter in a method that runs in the background. After this method is called I then have problems from that point forward with that context even though all I did was get a property value.
From the docs:
Any time you manipulate or access managed objects, you use the associated managed object context. Core Data does not present a situation where reads are “safe” but
changes are “dangerous”—every operation is “dangerous” because every
operation has cache coherency effects and can trigger faulting.
I've been working with Core Data in multi-threaded apps for some time (also in pre-iOS 5 era, without parent contexts etc.). I suspect it does some threading voodoo (locks and stuff) under the hood. If you want to be 100% safe, in a background thread you can't call any method on a NSManagedObject if its NSManagedObjectContext has not been created on the same thread. Otherwise, Undefined Behavior may happen (I got some deadlocks, for example).

What's the point of using performBlockAndWait in new iOS5 NSManagedObjectContext?

I am modifying my program to use the new iOS5 style.
So I simply use this code:
NSManagedObjectContext *threadContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
threadContext.parentContext = [self managedObjectContextMainThread];
//threadContext.persistentStoreCoordinator= [self persistentStoreCoordinator]; //moc.persistentStoreCoordinator;// [moc persistentStoreCoordinator];
My new background ManagedObjectContext doesn't have a persistentStore but have parent store instead.\
After that I suppose I am supposed to add
performBlockAndWait on all operation where I use all operation that use the new MOC.
I don't use that and doing just fine at least so far
performBlockAndWait is done by executing the block at the same thread and wait till it's complete.
What's the difference between that and just type the code like usual?
I mean there has to be some used, but I am totally missing here.
I can understand performBlock. That'll be like executing something in back ground. Even then it's superseded with Global Central Dyspatch.
Yes there is this new thing called Queue. Okay, if we do something on the same thread, of course everything is done consecutively. Duh.... So why the queue?
Anyone care to explain?
It is possible that the thread that execute the block is not the same with the thread that call performBlockAndWait.
For example, some core data object may only be able to be executed at main thread.
Hence, the performBlockAndWait would do it on a main thread (different thread) and block the current thread.
Also it's saver. Core data would lock things up appropriately preventing collision. If you have several thread accessing the same managed object context, you need to pull this up.
The reason for performBlockAndWait: is it will get and hold the concurrency lock to access Core Data. You can consider it a modernization of the lock/unlock approach, but that's undocumented implementation detail.
If you just execute the code directly, it won't do proper concurrency locking. This is interesting for a number of reasons:
Requests to Core Data won't be properly serialized. That is, if you performBlock: (no wait) the code could end up executing at the same time as other Core Data code, which would probably cause a problem in the coordinator or persistent store.
It… well, I actually don't think it should work. It seems to most of the time in practice, but you're running Core Data without necessary locks. Pretty sure you're into undocumented behaviour here at a minimum.
So:
performBlockAndWait: sets up an environment where your block can access Core Data via the context and waits for the block to complete.
The documentation says nothing about the thread. It's not actually documented as running on the current thread.
Even if it doesn't now, it could be changed in the future to go to secondary threads in at least some circumstances.
Read the parent point again: That's what you're supposed to rely on. The rest is just details.
performBlock: sets up an environment where your block and access Core Data via the context and does not wait for the block to complete.
The documentation says nothing about the thread. It's not actually documented as running on a different thread.
Although unlikely, a future version of the OS could decide to run the block on the current thread at a later time.
Again, the parent point is what you're to rely on. The rest is undocumented details.
I hope that helps. Basically, you're supposed to play dumber than you are when touching these calls. Let the OS do the right thing, just try not to make assumptions about what it's doing. :)
The NSPrivateQueueConcurrencyType constant sets up too many expectations for how this works.

Thread safety of UIImage

I know that Apple officially recommends UIKit to be used in the main thread only. However, I've also heard claims that UIImage is thread-safe since iOS 4.0. I cannot find any documentation backing this claim.
Does anyone have any information to support this claim? As a class used to store data and decode image data, UIImage should be thread-safe if well designed.
Directly from Apple's documentation for UIImage
Image objects are immutable, so you cannot change their properties after creation. This means that you generally specify an image’s properties at initialization time or rely on the image’s metadata to provide the property value. It also means that image objects are themselves safe to use from any thread. The way you change the properties of an existing image object is to use one of the available convenience methods to create a copy of the image but with the custom value you want.
(Emphasis mine)
So at least in the current version of the SDK as of May 13, 2014, "image objects are themselves safe to use from any thread."
It is true that apple recommends using elements from the UIKIt on the main thread:
Note: For the most part, UIKit classes should be used only from an
application’s main thread. This is particularly true for classes
derived from UIResponder or that involve manipulating your
application’s user interface in any way.
Since UIImage isn't derived from UIResponder, and you do not actually display it on the interface/screen. Then doing operations with UIImages on another thread should be safe.
This is however based on my experience, I haven't seen any official documentation about it.
It looks like Apple have updated their documentation since the earlier answers here were posted. According to the most up-to-date documentation, it is safe to create and use UIImage instances from any thread:
Because image objects are immutable, you cannot change their
properties after creation. Most image properties are set automatically
using metadata in the accompanying image file or image data. The
immutable nature of image objects also means that they are safe to
create and use from any thread.
https://developer.apple.com/reference/uikit/uiimage
In the What's New in iOS: iOS 4.0 release notes, the UIKit Framework enhancements include this bit:
Drawing to a graphics context in UIKit is now thread-safe.
Specifically: The routines used to access and manipulate the graphics
context can now correctly handle contexts residing on different
threads. String and image drawing is now thread-safe. Using color and
font objects in multiple threads is now safe to do.
So UIImage is thread-safe on iOS 4.0 and later.
Just to make it short:
UIImage is not thread safe, or better does only work on the main thread,
as I have experienced in my current after some debugging.
I hope that helps.
I wish to have more clarity about this from Apple
or even better an UIImage class, that could be rendered in a different thread.
Shouldn't be too difficult ...
edit:
After some research, I found that it is "UIGraphicsGetImageFromCurrentImageContext();"
that causes the trouble.
it's a bit off the topic, but maybe this helps:
https://coderwall.com/p/9j5dca
Thanks to Zachary Waldowski.
Thread-safe is not the issue, in that any thread can attempt to access a context at the same time (concurrently). And, while that is generally okay, in low-memory situations, like with a Photo Editing Extension on iOS devices, two threads accessing one context can crash an app due to low memory.
This happens when mixing Core Image filters with vImage operations. Both are thread-safe, but ARC will not release vImage buffer data before processing a Core Image object, so you have at some point two copies of an image in memory.
Accordingly, you never consider your knowledge of thread safety to be complete without understanding of threading and concurrency—and that goes double for any answer to questions about thread safety. In short: the proper question is, how does thread-safety apply to memory usage, whenever you're talking about image processing.
If you're just kicking the tires here, you need to wait to pose your question until you've encountered a real problem. But, if you're planning your next move, you need to know how to execute image processing commands sequentially, and with manual deallocation. You must design your app so that there is only one copy of the image being processing in memory. Never rely on automatic deallocation—thread-safe or not—to make that call for you. IT WILL NOT WORK.

Identify a GCD thread

I have written a Core Data abstraction class which holds the persistent store, object model and object context. To make the multithreading easier, I have written the accessor for the object context so that it returns a instance that is only available for the current thread by using [NSThread currentThread] to identify the threads.
This works perfectly as long as I don't use GCD, which I want to use as replacement for the old NSThread's. So my question is, how do I identify a GCD thread? The question applies for both iOS and Mac OS X but I guess that its the same for both platforms.
You could check whether dispatch_get_current_queue() returns anything. I like Jeremy's idea of transitioning to a CD-context-per-queue instead of CD-context-per-thread model using the queue's context storage though.
Perhaps you can store the CD context for each thread in the GCD context using dispatch_set_context()
The contextForCurrentThread helper method in Magical Record is very similar to what to said (i.e. keep one context per thread). The GCD execution block, while running on a single queue, can potentially run on any thread managed by GCD, which will cause some random crashes. Check this article: http://saulmora.com/2013/09/15/why-contextforcurrentthread-doesn-t-work-in-magicalrecord/

Undoing Core Data insertions that are performed off the main thread

I'm working on some code that uses an NSOperation to import data. I'd like for the user to be able to undo the NSManagedObject instances that are created during the import operation.
From what I can tell, it's impossible to use the NSManagedObjectContext -undoManager for any operations that are performed off of the main thread. From the Core Data Programming Guide section on Use Thread Confinement to Support Concurrency, we have these two conditions:
Only objectID should be passed
between managed object contexts (on
separate threads)
Managed objects
must be saved in a context before
the objectID can be used.
This makes sense since the managed objects need to be moved from private storage (NSManagedObjectContext) to public storage (NSPersistentStore) before they can be shared.
Unfortunately, the -save: message also causes any managed objects in the undo stack to be removed. From the Memory Management Using Core Data section of the same guide:
Managed objects that have pending
changes (insertions, deletions, or
updates) are retained by their context
until their context is sent a save:,
reset , rollback, or dealloc message,
or the appropriate number of undos to
undo the change.
I've tried several things to work around this limitation, and everything eventually leads back to bulk of the work happening on the main thread (and spinning beach balls.) Any clues to getting undo working with objects created off the main thread would be very much appreciated.
--
An enhancement Radar has been submitted: rdar://problem/8977725
This answer will probably be a bit of a back and forth. If I understand the issue correctly, you are doing an import but when the import is done you want the user to be able to select what gets saved from the import?
If that is not correct, please fix my assumptions and I will update this answer.
If it is correct then what you can do is:
Change your background object creation to
NSEntityDescription *myEntity = ... //Entity from your context
[[NSManagedObject alloc] initWithEntity:myEntity
insertIntoManagedObjectContext:nil];
Store these entities in an array.
Pass the entities back to your main thread as needed.
Release on any objects you don't want to keep
Call [myMainContext insertObject:managedObject] on any you want to keep.
Perform a save on the NSManagedObjectContext.
Since these entities are not part of a NSManagedObjectContext yet they only exist in memory and should be thread safe since they are not yet tied down to a NSManagedObjectContext.
This is of course theoretical and will require testing. However it should accomplish your goal.
Not an expert, but I think what you're going to need to do is create a second context to perform the operations, then merge the two contexts together. You should be able to manage the merge as an undo step. Note, this only works if you're treating the entire set of operations as one undo step, as far as the user is concerned.
Suppose that you use a separate context for the background thread, and once it's done, push a [[backgroundContext undoManager] undo] onto the foreground thread's undo stack? I've never tried anything like that, but off the top of my head I can't think of a reason it shouldn't work.
One option may be to make your import thread persistent. Even when the thread is finished importing, it goes into an idle loop state. This way your threaded ManagedObjectContext is persisted in the proper thread. Then when the user wishes to undo a change, send a message to the thread to use the undomanager.
It's incredibly likely you've considered this and you're likely only looking for a solution using the existing undoManager, but just in case:
Since you're inserting objects and not updating existing ones, you do have the power to tag them with a transaction id as each batch is imported, deleting them in a background thread in the case of an undo. A simple incremented NSNumber is sufficient for the tag.
Inelegant, but workable.