|Number of watchers on Github||136|
|Number of open issues||1|
|Average time to close an issue||about 14 hours|
|Average time to merge a PR||about 1 hour|
|Open pull requests||0+|
|Closed pull requests||0+|
|Last commit||over 6 years ago|
|Repo Created||over 6 years ago|
|Repo Last Updated||over 2 years ago|
|Organization / Author||tumblr|
|Do you use CoreDataExample? Leave a review!|
|View CoreDataExample activity|
|View on github|
|Book a Mock Interview With Me (Silicon Valley Engineering Leader, 100s of interviews conducted)|
Software engineers: It's time to get promoted. Starting NOW! Subscribe to my mailing list and I will equip you with tools, tips and actionable advice to grow in your career.
This is a sample project whose purpose is to gather feedback on the best way to use Core Data in a multithreaded environment. Here's a blog post explaining the motivation:
Weve been using Core Data for persistence in Tumblr for iOS for years now, but are always interested in re-evaluating our approach to make sure that were leveraging the SDK as effectively as possible.
The focal point is the TMCoreDataController class, which exposes a block-based API for updating managed object contexts both from the main queue as well as in the background.
The application simply fetches, persists, and displays a little bit of data from the Tumblr API, in order to provide a real-world example of how
TMCoreDataController is expected to be used.
TMCoreDataController is implemented using three-levels of parent/child managed object contexts (based off of the suggestions made in this blog post):
Write operations should only be done through
performMainContextBlock: methods, both of which save the context being written to as well as any parent contexts (recursively) immediately after.
In this particular example, the heavy lifting of updating our database with new posts is done in
refresh method. The code in this particular project is pretty simple and contrived, but assume that a lot more work would be done here in a real production app. It is expected that user interaction may result in updates to the main queue's context while this background block is being executed.
To run the sample application, you need to add OAuth keys, tokens, and secrets to TMAppDelegate. If you don't already have one, you can create a Tumblr API application here and generate a token and secret using our API console.
What problems are there with this approach? How could this be improved?
Is the recursive managed object context save the best way to ensure that all of our data is kept in sync?
I'm worried that this architecture makes us susceptible to deadlocks, as outlined in this article:
With NSFetchedResultsController and nested contexts, its pretty easy to do. Using the same UIManagedDocument setup described above, executing fetch requests in the private queue context while using NSFetchedResultsController with the main queue context will likely deadlock. If you start both at about the same time it happens with almost 100% consistency. NSFetchedResultsController is probably acquiring a lock that it shouldnt be. This has been reported as fixed for an upcoming release of iOS.
Unfortunately I've seen a couple of crashes which may corroborate the above, such as:
Incident Identifier: 5168BD71-BFD2-4DF6-84C4-240364B888DD CrashReporter Key: 289E38A8-3E8A-41CB-877F-1FEEF852AF30 Hardware Model: iPhone6,1 Version: 251 Code Type: ARM-64 Parent Process: launchd  Date/Time: 2014-05-13T01:23:26Z OS Version: iPhone OS 7.1.1 (11D201) Report Version: 104 Exception Type: SIGSEGV Exception Codes: SEGV_ACCERR at 0xbf02beb8 Crashed Thread: 0 Application Specific Information: objc_msgSend() selector name: isFault Thread 0 Crashed: 0 libobjc.A.dylib 0x00000001978fc1d0 objc_msgSend + 16 1 CoreData 0x000000018b1782a8 __92-[NSManagedObjectContext(_NestedContextSupport) newValuesForObjectWithID:withContext:error:]_block_invoke + 276 2 libdispatch.dylib 0x0000000197ec3fd4 _dispatch_client_callout + 12 3 libdispatch.dylib 0x0000000197ec9c84 _dispatch_barrier_sync_f_invoke + 44 4 CoreData 0x000000018b16ccec _perform + 120 5 CoreData 0x000000018b178150 -[NSManagedObjectContext(_NestedContextSupport) newValuesForObjectWithID:withContext:error:] + 124 6 CoreData 0x000000018b0e8b00 _PFFaultHandlerLookupRow + 356 7 CoreData 0x000000018b0e8604 _PF_FulfillDeferredFault + 252 8 CoreData 0x000000018b0e8458 _sharedIMPL_pvfk_core + 60 9 ExampleApplication 0x00000001000887cc 0x100054000 + 214988 10 ExampleApplication 0x00000001000625c0 0x100054000 + 58816 11 libdispatch.dylib 0x0000000197ec4014 _dispatch_call_block_and_release + 20 12 libdispatch.dylib 0x0000000197ec3fd4 _dispatch_client_callout + 12 13 libdispatch.dylib 0x0000000197ec9ea8 _dispatch_after_timer_callback + 76 14 libdispatch.dylib 0x0000000197ec3fd4 _dispatch_client_callout + 12 15 libdispatch.dylib 0x0000000197ec5b90 _dispatch_source_invoke + 496 16 libdispatch.dylib 0x0000000197ec7180 _dispatch_main_queue_callback_4CF + 240 17 CoreFoundation 0x000000018b3a2c2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8 18 CoreFoundation 0x000000018b3a0f6c __CFRunLoopRun + 1448 19 CoreFoundation 0x000000018b2e1c20 CFRunLoopRunSpecific + 448 20 GraphicsServices 0x0000000190fc9c0c GSEventRunModal + 164 21 UIKit 0x000000018e412fdc UIApplicationMain + 1152 22 ExampleApplication 0x000000010005df3c 0x100054000 + 40764 23 libdyld.dylib 0x0000000197edfaa0 start + 0
How can this be mitigated, other than just optimizing all of our fetches and saves to prevent the persistent store coordinator from being locked for longer than it needs to be?
Marcus provides a ton of free Core Data help on Stack Overflow as well as on Twitter, you should support him by checking out his Core Data book.