Re: Core Data concurrency during import of folder contents
Re: Core Data concurrency during import of folder contents
- Subject: Re: Core Data concurrency during import of folder contents
- From: Roland King <email@hidden>
- Date: Sat, 31 Jan 2015 09:23:50 +0800
> On 31 Jan 2015, at 01:20, Steve Mills <email@hidden> wrote:
>
> I'm trying to learn Core Data. I have a working document model hooked up to a table view (OS X). I have an import method that uses FSDirectoryEnumerator to add an object for each file in the folder. Oky doke! But that blocks for a few seconds while it loops. So I'm trying to make it threaded. One example I saw uses GCD. It kinda seemed to work when I had a bunch of printfs in there so I could watch it progress, but when I took them out it just crashed at some point, and it still blocked any sort of user events.
>
> Next I tried sticking the entire import operation into a block via NSOperationQueue's addOperationWithBlock:. That throws because some set was being changed by multiple threads. Then I tried the suggestion of using a private NSManagedObjectContext in the block. That got me somewhere, but of course the data didn't populate my table. I tried the NSManagedObjectContextDidSaveNotification trick, but I couldn't get that to work.
>
> Reading the Concurrency with Core Data page online says the information is outdated. Where do I find current documentation? Or better yet, an actual example that actually works? My brain is about to explode, and nobody wants to clean that up.
>
Oh yes the documentation does say that doesn't it - that's a shame. My first recommendation right off the bat (and it's the same one I make often) is to go watch the core data videos from WWDC going back to about 2011 when I believe all the 'new' concurrency was introduced. It's a time-investment but there's loads of good stuff in there which I find helps immensely and you really can't find out any other way. (The 2014 video has a brief runthrough towards the start of the history of concurrency with Core Data, that's at least a start).
At this point, NSThreadConfinementCurrencyType, the default since confinement types were introduced, is basically obsolete and there was a warning in the 2014 WWDC video that it's going to go away. The concept of worrying about threads has really gone away with it. So you don't need your own operations queues, you should use an MOC which is NSPrivateQueueConcurrencyType and .. this is important .. send all requests to it on with performBlock: or performBlockAndWait: method. This will happily use GCD under the hood and serialize on the queue. Your UI should use an NSMainQueueConcurrencyType usually, because then you're always on the right queue when updating your UI.
Two ways to get the results back into the MOC which is backing your table, one which you probably currently created as a default MOC with NSConfinementCurrencyType (the default) but which you should possibly think about changing to the main queue type. Then you have a couple of options, you can have an entirely separate MOC in which you do your import, or you can make a child MOC of the main one, of type NSPrivateQueueConcurrencyType, and do the import then, then 'save' it which will push the changes into the parent. I've done both, I prefer the separate MOC approach for bulk data import and use the child context paradigm mostly for discardable edits, for which it's really well-suited.
NSManagedObjectContextDidSaveNotification is regrettably not a trick, it's how different MOCs talk to each other. So you need to get that to work. I think when I started with Core Data I tried hard to avoid it because I don't 'do' notifications, and then I gave up trying to avoid it, figured it out once and used it. What about it couldn't you get to work? When a context saves it sends that notification (plus another one before and one after to tell you things have changed and that it was saved) to anyone who cares to listen, it's that simple (as long as you called save). Core Data itself is very good at updating your local MOC with the results of such a notification, you really just need to get the notification and hand it to your MOC to figure out. If you want to be clever about it and inspect the notification to figure out exactly what objects changed and how to update your UI minimally, you can do that, a first dumb approach is get notification, call core data method to update local MOC, call reloadData on your table. Not pretty but a place to start.
So I'd say probably go back to the notification and figure out what it was you were having problems with there, if you want a background import, you're going to need to get to the bottom of that.
_______________________________________________
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