Re: Threads and Core Data, bindings results in view corruption
Re: Threads and Core Data, bindings results in view corruption
- Subject: Re: Threads and Core Data, bindings results in view corruption
- From: Jeff LaMarche <email@hidden>
- Date: Mon, 31 Mar 2008 14:26:14 -0400
David:
I can't speak for Apple (I'll leave that to Ben), but there are a few
things to keep in mind here:
1) Core Data is still a relatively new technology. Sure, it came out
with Tiger, but since using it keeps your app from running on earlier
versions of OS X, a lot of software projects never adopted its use.
When using traditional objective-C persistence (e.g. NSCoder) a lot of
these issues don't exist, so until we hit critical mass of developers
using Core Data in their apps, a lot of these issues will persist
(especially if we don't file enhancement requests, as Ben pointed out,
something I am admittedly guilty of)
2) Core Data, although relatively new, borrowed a lot conceptually
from EOF, which was part of WebObjects, a web application framework. A
lot of the concurrency issues we're talking about didn't exist in
WebObjects because the UI was all rendered through HTML. The stateless
nature of HTTP connections and the types of tasks you do in web apps
rendered it mostly a non-issue.
3) Often, there are other ways to deal with UI responsiveness other
than threads. Sure, it's the first thing that jumps to mind (at least
for me), but two other possibilities that I can think of are timers
and run loop callbacks like those used in CFNetwork. In fact, that's
how I got around the problem in my app - I simply buffer and process
chunks of data in a callback method the way CFFoundation does. Doing
that, I lose the performance benefits of threads, but I didn't need
that anyway, and my code is much easier to debug and maintain.
4) You can, as Ben mentioned, use performSelector:onMainThread: to
actually have the object inserted on the main thread's context. It's a
bit of a pain, but threads are always at least a little painful.
Just my 2ยข... Like you, I'd still like to see Core Data become fully
thread-safe, but you can't always have what you want when you want it.
Jeff
On Mar 31, 2008, at 1:49 PM, David wrote:
Thank you very much for the response which is chock full of helpful
information. Its taken me some time to try and digest.
I must admit being a little demoralized. I've always considered
threading to go hand and hand with GUI programming. I'm having
trouble envisioning the scenarios where bindings and core data are
intended to be used without threads.
I'm relatively new to Cocoa. From my previous work in win32 and Java
this is the normal scenario, not an unusual one. Can someone point
me to some sample code that illustrates how to have a worker thread
updating data which is displayed in the UI?
In my case I am/was trying to maintain a outline view representing
files, storing each node in core data. Based on these responses I'm
not sure what technologies I should reasonably be using. Is this too
fine grained for Core Data? Should I give up on bindings? Should I
give up on NSTreeController?
If I try to maintain multiple MOCs, that means I have to save to get
it to show up in the other moc, right? The save as binary file can
take 15 seconds in my case when I have thousands of nodes. That
hangs the UI longer than adding the nodes to start with. Should I
try to use a in memory persistent store or will that still be slow
or cause an excessive memory penalty?
Additional comments below:
On Sun, Mar 30, 2008 at 9:50 PM, Ben Trumbull <email@hidden>
wrote:
If you want multi-threaded work with the view and controller classes
in Cocoa, you'll need to perform your background operations, and
communicate back to the main thread (view & controllers) via the run
loop. -performSelectorOnMainThread and its friends in NSThread.h are
your best bet.
Using a run loop on a background thread and communicating from the
main thread to it with the new 10.5 -performSelector... methods is
often conceptually simpler (easier to debug) than many other
threading patterns.
Sharing a MOC with Cocoa Bindings and a background thread will end in
tears. Cocoa Bindings doesn't lock its bound MOC, so you're
basically SOL.
Can I ask why don't bindings lock the bound MOC or provide the
option to? I had assumed (incorrectly) that bindings would handle
threads OR provide some means to control or configure its threading
behavior.
Even if it did work, though, it'd be a bad idea. Sharing a MOC means
a background thread would still at times block the main thread and
SPOB your app.
Why doesn't core data support locking at a finer grain? Or to
rephrase, it would be very helpful if Core Data could lock at a
ManagedObject level. I expected there to be a locking or transaction
mode where I can lock it while I fill in an object. Nothing else
should require me to worry about core data getting corrupted with
multiple threads.
These 3 points (can't work, doesn't work, shouldn't work) are why the
Core Data Programming Guide says don't do this.
The Core Data programming guide in the threading section guidelines
states:
"3) Pass managed objects or managed object contexts between threads.
This approach is strongly discouraged. You must ensure that you
apply locks as appropriate and necessary."
I have interpreted that to mean that locking the
managedObjectContext would be sufficient. I hadn't realized that
bindings would try to obtain locks.
The list archives also have these, which you should read:
<http://lists.apple.com/archives/cocoa-dev/2007/May/msg00222.html>
<http://lists.apple.com/archives/cocoa-dev/2008/Jan/msg01889.html>
It's possible to shuttle pending changes between threads by hand
using KVC.
Are you describing in general or specifically with Core Data? Can
you give more insight on this? Are you saying that I manually track
changes from core data?
If its my own objects, I would expect to manage fine grain locks or
synchronize code which modifies by object tree.
If you're inserting a large number of new objects, you really should
just batch the operation together, save, and present the user with
new objects in the tree view in batches.
On Leopard, in the scenarios under which you can save, you can also
use -mergeChangesFromContextDidSaveNotification:
But isn't a notification received on the same thread on which it was
posted?
Finally, in 4 years no one has filed a bug about this.
File a bug about what? Do you consider the threading behavior in
bindings and Core data to be a bug?
--
-Ben
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden