SlideShare a Scribd company logo
Adventures in
Multithreaded Core Data
    CocoaheadsBE - Zoersel, 2012-09-24
Introduction
Adventures in Multithreaded Core Data
Tom Adriaenssen
I love...
‣ ... my wife
‣ ... my 4 kids
‣ ... to code
‣ ... to play a game of squash
‣ ... good beer
I open sourced...
... some code:

‣ IIViewDeckController: “An
  implementation of the
  sliding functionality found in
  the Path 2.0 or Facebook
  iOS apps.”

‣ IIDateExtensions

‣ IIPopoverStatusItem

See: http://github.com/inferis
I made...
... some apps:




         Butane                     Drash
     http://getbutane.com          http://dra.sh

         Hi, @10to1!
Butane
                        Campfire client for iOS

‣ Official Campfire client
  kinda sucks, so we
  rolled our own

‣ Somewhat concurrent
  app

‣ Uses Core Data

‣ Together with 10to1
This presentation is about
      what I learned
  while coding Butane.
Agenda
Agenda

‣ Core Data Primer
‣ MagicalRecord
‣ Concurrency problems
‣ Concurrency solutions
Core Data Primer
What is: Core Data?
                ‣ Per the documentation:
                ‣ The  Core  Data  framework  provides  
                  generalized  and  automated  solutions  
                  to  common  tasks  associated  with  
                  object  life-­‐cycle  and  object  graph  
                  management,  including  persistence.




http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/CoreData/Articles/cdTechnologyOverview.html#//apple_ref/doc/uid/TP40009296-SW1
Wait, what?
What isn’t: Core Data?

‣ It’s not an RDBMS.
‣ If you want a database and SQL, use
  Sqlite:
What isn’t: Core Data?

‣ It’s not just an ORM (Object Relational
  Mapper)
‣ It may look like there’s SQL under the
  hood, but that’s not necessarily the case.
So, what is it then?
Core Data provides:
‣ persistence
‣ change tracking
‣ relations (object graph)
‣ lazy loading (“faulting”)
‣ validation
‣ works well with Cocoa (KVO, KVC)
Basically:

‣ A system to store data
‣ Persistence agnostic (local storage,
  iCloud, AFIncrementalStore, ...)
‣ No need to write SQL to query
‣ You can keep to Objective-C
Your tools:
‣ NSPersistentStore
‣ NSManagedObjectContext
‣ NSManagedObject
‣ NSManagedObjectID  
‣   NSFetchRequest
‣   NSEntityDescription
‣   NSPredicate
‣   NSSortDescription
A picture says a 1000 words...
MagicalRecord
MagicalRecord
           ‣ Writing Core Data code is tedious.
           ‣ You need quite a bit of boilerplate code
             to do something simple:

NSManagedObjectContext  *moc  =  [self  managedObjectContext];
NSEntityDescription  *entityDescription  =  [NSEntityDescription  entityForName:@"Employee"  inManagedObjectContext:moc];
NSFetchRequest  *request  =  [NSFetchRequest  new];
[request  setEntity:entityDescription];
  
NSSortDescriptor  *sortDescriptor  =  [[NSSortDescriptor  alloc]  initWithKey:@"firstName"  ascending:YES];
[request  setSortDescriptors:@[sortDescriptor]];
  
NSError  *error;
NSArray  *array  =  [moc  executeFetchRequest:request  error:&error];

if  (array)
{
           //  display  items  (eg  in  table  view)
}
else  {
        //  Deal  with  error...
}
MagicalRecord
‣ MagicalRecord tries to solve this.


‣ = ActiveRecord pattern for Core Data.
‣ Encapsulates the tediousness of plain
  Core Data code.
MagicalRecord
           ‣ Writing MagicalRecord enable code is
             tedious no more:
           ‣ That same example is now this:


NSManagedObjectContext  *moc  =  [self  managedObjectContext];
NSArray  *array  =  [Employee  MR_findAllSortedBy:@"firstname"  ascending:YES  inContext:context];

if  (array)
{
           //  display  items  (eg  in  table  view)
}
else  {
        //  Deal  with  error...
}
Adventures in Multithreaded Core Data
Great, isn’t it?
MagicalRecord
+ write less code
+ your code becomes more readable
+ good for apps requiring simple storage scenarios (=most
  apps, probably)
+ hides complexity
-   hides complexity
-   easy to start, but diving deeper becomes harder
- uses defaults that are suboptimal in a multithreaded app
- concurrency errors and issues are subtle
MagicalRecord
‣      used MagicalRecord from the start
‣ Took me a while to find out the problems
  I was having were related to the
  complexity hiding
‣ The defaults are okay only for so much
  app complexity
MagicalRecord
‣ That said: Magical Record is great.
‣ It will speed up your Core Data
  development by several factors.
‣ Also: take a look at mogenerator:
 ‣   http://rentzsch.github.com/mogenerator/

 ‣   or: brew  install  mogenerator
MagicalRecord

‣ So I threw it out.
MagicalRecord

‣ So I threw it out.
‣ But not completely.
MagicalRecord

‣ So I threw it out.
‣ But not completely.
‣ More about that later.
The problems described hereafter only apply
to the persistent stores with external backing
             (for example: sqlite).
Concurrency: problems
Problems?
Problems?

‣ Core Data Objects are not thread safe.
Problems?

‣ Core Data Objects are not thread safe.
‣ In essence: you can’t share them across
  threads (except for NSManagedObjectID).
Problems?

‣ Core Data Objects are not thread safe.
‣ In essence: you can’t share them across
  threads (except for NSManagedObjectID).
‣ Core Data locks objects, even for read
  operations.
Object storage is locked
for read operations, too
‣ Objects used to power the UI must be
  fetched on the UI thread.
‣ Heavy/complex fetch requests (queries)
  block the UI thread while fetching the
  objects. You don’t want that.
Objects aren’t supposed to
be shared between threads
‣ The NSManagedObjectContext “locks” an
  object when you read one of its properties.
‣ This can cause a deadlock when you do
  access the same data from 2 threads.
‣ Reason: faulting support can change the
  object even while just reading from it.
‣ You can’t turn it off.
Adventures in Multithreaded Core Data
Luckily, we can fix or workaround these
               problems.
Concurrency: solutions
Keep to your thread
Keep to your thread


‣ pre-iOS5: use thread confinement
Keep to your thread


‣ pre-iOS5: use thread confinement
‣ iOS5 and later: use nested contexts
Thread confinement
‣ In essence: keep an NSManagedObjectContext per
  thread
‣ Be very careful when going from one thread to
  another.


‣ MagicalRecord tries to hide this from you:
  ‣ It automatically provides a context for each thread
  ‣ This is a bit counterintuitive since you start mixing
    objects across threads quite easily.
Thread confinement




     Image source: Cocoanetics
Nested contexts
‣   Introduced in iOS5
‣   Uses Grand Central Dispatch and dispatch queues
‣   Core Data manages threading for you
‣   Better than thread confinement
    ‣   more straightforward
    ‣   more flexible


‣   MagicalRecord hides this from you, too.
    ‣   Automatically switches to dispatch queues on iOS5 even
        though the API remains the same.
Nested contexts




    Image source: Cocoanetics
Nested contexts
‣ NSManagedObjectContext = cheap
‣ You can nest contexts
‣ Each context has its private dispatch
  queue
‣ No manual thread synchronization
  necessary
Queue types
    ‣ NSConfinementConcurrencyType
        ‣     The old way (thread confinement)

    ‣ NSPrivateQueueConcurrencyType
        ‣     The context has its own private dispatch queue

    ‣ NSMainQueueConcurrencyType
        ‣     The context is associated with the main queue (or runloop, or UI
              thread)


parentMoc  =  [[NSManagedObjectContext  alloc]  initWithConcurrencyType:NSMainQueueConcurrencyType];
[parentMoc  setPersistentStoreCoordinator:coordinator];

moc  =  [[NSManagedObjectContext  alloc]  initWithConcurrencyType:NSPrivateQueueConcurrencyType];
moc.parentContext  =  parentMoc;
Thread safe?
   ‣ performBlock:   
     performBlockAndWait:
   ‣ Run a block you provide on the queue
     associated with the context.
        ‣ Object access in the block is thread safe
[context  performBlockAndWait:^{
        for  (Room*  room  in  [Room  findAllInContext:context])  {
                room.joinedUsers  =  [NSSet  set];
                room.knowsAboutJoinedUsersValue  =  NO;
                room.unreadCountValue  =  0;
                room.status  =  @"";
        }
        NSError*  error  =  nil;
        [context  save:&error];
}];
performBlock, and wait
-­‐  (void)performBlock:(void  (^)())block;
   ‣   executes the block on the context dispatch queue as soon as possible

   ‣   nonblocking call

   ‣   code will not execute immediately



-­‐  (void)performBlockAndWait:(void  (^)())block;
   ‣   executes the block on the context dispatch queue immediately

   ‣   blocks the current execution until block is done

   ‣   can cause a deadlock (if you’re already running code on the same
       queue)
When to use what?
‣   performBlock:
    ‣   For actions which are “on their own”
    ‣   Consider the code in the block a Unit Of Work
    ‣   Best for save operations
    ‣   Useful for long fetches (use callbacks)


‣   performBlockAndWait:
    ‣   When you need stuff immediately
    ‣   Good for small fetches or “standalone” saves
How is this better than
 thread confinement?
‣ No manual thread handling, Core Data
  handles it for you.
‣ More flexible: as long as you access
  managed objects in the correct context
  using performBlock: you’re pretty safe
 ‣ also applies to the main/UI thread! (unless
   you’re sure you’re on the main thread)
Saving nested contexts
‣ Saves are only persisted one level deep.
‣ Parent contexts don’t pull changes from
  child contexts.
‣ Child contexts don’t see changes by
  parent contexts.
 ‣   Make them plenty and short-lived
How to nest contexts

‣ 2 approaches:
 ‣ root context = NSMainQueueConcurrencyType
 ‣ root context = NSPrivateQueueConcurrencyType
Root = Main
                              ‣ Many child contents
                                with private queues

                              ‣ Root context on main
                                queue

                              ‣ Actual persistence
                                happens on main
                                queue, could block the
                                UI

  Image source: Cocoanetics
Root = Private
                         ‣ Root context with private
                           queue

                         ‣ Many child contents with
                           private queues

                         ‣ context on main queue is
                           child of root

                         ‣ Actual persistence
                           happens in background
                           (does not block the UI)

   Image source: Cocoanetics
What problems did we
    have again?
What problems did we
    have again?

‣ No sharing of NSManagedObjects
  between threads.
What problems did we
     have again?

‣ No sharing of NSManagedObjects
  between threads.
‣ Context locking
Sharing: solution
‣ Pass only NSManagedObjectIDs to
  other threads, not objects.
‣ Refetch the object on a different thread
  or queue to work with it.
‣ Don’t forget to save the ‘original’ object
  first before working with it on the second
  thread or queue.
Complex queries
‣   Use the same technique for complex or large queries.
    1. do the heavy lifting in the background
    2. pass list of NSManagedObjectIDs to another thread
       (e.g. UI thread).
    3. load objects as faults, and let Core Data fault them in
       when you need them (e.g. when accessing a property)


‣   That’s lot of requests, but this is actually more performant
    and desirable in most cases.
Locking: solution
‣ Use child contexts with their own
  dispatch queues.
‣ Use: performBlock: and
  performBlockAndWait:  carefully.
‣ Deadlocks still possible, especially with
  performBlockAndWait:
A word about
 NSManagedObjectIDs
‣ Two types of IDs:
 ‣ temporary
   ‣ when the object hasn’t been persisted to a
     store

 ‣ permanent
   ‣ when the object has been persisted to a
     store
A word about
 NSManagedObjectIDs
‣ Subtle bug: temporary IDs from a non-root
  context don’t get updated to permanent
  IDs when saving in the root context
‣ The object is saved just fine, but the ID is
  not updated correctly.
‣ When passing these around to other
  contexts after saving: you won’t find the
  object in another child context!
A word about
 NSManagedObjectIDs

‣ To the rescue:
  -­‐  (BOOL)obtainPermanentIDsForObjects:
  (NSArray  *)objects  error:(NSError  
  **)error;
A word about
  NSManagedObjectIDs
   -­‐  (BOOL)obtainPermanentIDsForObjects:(NSArray  
   *)objects  error:(NSError  **)error;



‣ Transforms objects with temporary IDs to permanent IDs
  (through the persistent store of the root context).
‣ Do this when creating a managed object and you’re
  safe.
‣ Obtaining permanentIDs is batched, so the performance
  hit is not that high
MagicalRecord
‣ I still use MagicalRecord:
 ‣ Reduced form: no more “automatic”
   context handling --> dangerous!
 ‣ Added some extra sauce to work with
   the nested contexts.
 ‣ The methods MR supplies still allow for
   a speedup when coding.
Useful References


‣   Nested context release notes: http://developer.apple.com/library/mac/#releasenotes/
    DataManagement/RN-CoreData/_index.html
‣   Magical Record: https://github.com/magicalpanda/MagicalRecord
‣   Mogenerator: http://rentzsch.github.com/mogenerator/
‣   A good read on Cocoanetics: http://www.cocoanetics.com/2012/07/multi-context-coredata/
‣   Core data programming guide: http://developer.apple.com/library/mac/#documentation/
    cocoa/Conceptual/CoreData/cdProgrammingGuide.html
‣   Butane: http://getbutane.com
Thanks for listening.


Questions? Contact me:

Twitter: @inferis
App.Net: @inferis
E-mail: tom@interfaceimplementation.be
vCard: http://inferis.org
Ad

More Related Content

What's hot (20)

Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCA
Whymca
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JS
Cosmin Mereuta
 
Polyglot persistence with Spring Data
Polyglot persistence with Spring DataPolyglot persistence with Spring Data
Polyglot persistence with Spring Data
Corneil du Plessis
 
Getting Started with Datatsax .Net Driver
Getting Started with Datatsax .Net DriverGetting Started with Datatsax .Net Driver
Getting Started with Datatsax .Net Driver
DataStax Academy
 
Mongo performance tuning: tips and tricks
Mongo performance tuning: tips and tricksMongo performance tuning: tips and tricks
Mongo performance tuning: tips and tricks
Vladimir Malyk
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
Tomáš Kypta
 
MongoDB: tips, trick and hacks
MongoDB: tips, trick and hacksMongoDB: tips, trick and hacks
MongoDB: tips, trick and hacks
Scott Hernandez
 
Getting started with node JS
Getting started with node JSGetting started with node JS
Getting started with node JS
Hamdi Hmidi
 
Hazelcast
HazelcastHazelcast
Hazelcast
oztalip
 
Nuvola: a tale of migration to AWS
Nuvola: a tale of migration to AWSNuvola: a tale of migration to AWS
Nuvola: a tale of migration to AWS
Matteo Moretti
 
iOS5 NewStuff
iOS5 NewStuffiOS5 NewStuff
iOS5 NewStuff
deenna_vargilz
 
Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5
Rainer Stropek
 
Java. Explicit and Implicit Wait. Testing Ajax Applications
Java. Explicit and Implicit Wait. Testing Ajax ApplicationsJava. Explicit and Implicit Wait. Testing Ajax Applications
Java. Explicit and Implicit Wait. Testing Ajax Applications
Марія Русин
 
MongoDB Performance Tuning and Monitoring
MongoDB Performance Tuning and MonitoringMongoDB Performance Tuning and Monitoring
MongoDB Performance Tuning and Monitoring
MongoDB
 
Birhanu distributive assignment
Birhanu distributive assignmentBirhanu distributive assignment
Birhanu distributive assignment
university
 
Pycon 2012 Apache Cassandra
Pycon 2012 Apache CassandraPycon 2012 Apache Cassandra
Pycon 2012 Apache Cassandra
jeremiahdjordan
 
Introduction to Node.js Platform
Introduction to Node.js PlatformIntroduction to Node.js Platform
Introduction to Node.js Platform
Naresh Chintalcheru
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
Tomas Jansson
 
Zend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingZend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching logging
Tricode (part of Dept)
 
Whats new in iOS5
Whats new in iOS5Whats new in iOS5
Whats new in iOS5
Paul Ardeleanu
 
Beginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCABeginning icloud development - Cesare Rocchi - WhyMCA
Beginning icloud development - Cesare Rocchi - WhyMCA
Whymca
 
Scalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JSScalable network applications, event-driven - Node JS
Scalable network applications, event-driven - Node JS
Cosmin Mereuta
 
Polyglot persistence with Spring Data
Polyglot persistence with Spring DataPolyglot persistence with Spring Data
Polyglot persistence with Spring Data
Corneil du Plessis
 
Getting Started with Datatsax .Net Driver
Getting Started with Datatsax .Net DriverGetting Started with Datatsax .Net Driver
Getting Started with Datatsax .Net Driver
DataStax Academy
 
Mongo performance tuning: tips and tricks
Mongo performance tuning: tips and tricksMongo performance tuning: tips and tricks
Mongo performance tuning: tips and tricks
Vladimir Malyk
 
Modern Android app library stack
Modern Android app library stackModern Android app library stack
Modern Android app library stack
Tomáš Kypta
 
MongoDB: tips, trick and hacks
MongoDB: tips, trick and hacksMongoDB: tips, trick and hacks
MongoDB: tips, trick and hacks
Scott Hernandez
 
Getting started with node JS
Getting started with node JSGetting started with node JS
Getting started with node JS
Hamdi Hmidi
 
Hazelcast
HazelcastHazelcast
Hazelcast
oztalip
 
Nuvola: a tale of migration to AWS
Nuvola: a tale of migration to AWSNuvola: a tale of migration to AWS
Nuvola: a tale of migration to AWS
Matteo Moretti
 
Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5Whats New for WPF in .NET 4.5
Whats New for WPF in .NET 4.5
Rainer Stropek
 
Java. Explicit and Implicit Wait. Testing Ajax Applications
Java. Explicit and Implicit Wait. Testing Ajax ApplicationsJava. Explicit and Implicit Wait. Testing Ajax Applications
Java. Explicit and Implicit Wait. Testing Ajax Applications
Марія Русин
 
MongoDB Performance Tuning and Monitoring
MongoDB Performance Tuning and MonitoringMongoDB Performance Tuning and Monitoring
MongoDB Performance Tuning and Monitoring
MongoDB
 
Birhanu distributive assignment
Birhanu distributive assignmentBirhanu distributive assignment
Birhanu distributive assignment
university
 
Pycon 2012 Apache Cassandra
Pycon 2012 Apache CassandraPycon 2012 Apache Cassandra
Pycon 2012 Apache Cassandra
jeremiahdjordan
 
Introduction to Node.js Platform
Introduction to Node.js PlatformIntroduction to Node.js Platform
Introduction to Node.js Platform
Naresh Chintalcheru
 
Getting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NETGetting started with Elasticsearch and .NET
Getting started with Elasticsearch and .NET
Tomas Jansson
 
Zend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching loggingZend framework 03 - singleton factory data mapper caching logging
Zend framework 03 - singleton factory data mapper caching logging
Tricode (part of Dept)
 

Similar to Adventures in Multithreaded Core Data (20)

Connecting to a REST API in iOS
Connecting to a REST API in iOSConnecting to a REST API in iOS
Connecting to a REST API in iOS
gillygize
 
Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0
Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0
Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0
Cyber Security Alliance
 
The Theory Of The Dom
The Theory Of The DomThe Theory Of The Dom
The Theory Of The Dom
kaven yan
 
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
smn-automate
 
Hadoop: Big Data Stacks validation w/ iTest How to tame the elephant?
Hadoop:  Big Data Stacks validation w/ iTest  How to tame the elephant?Hadoop:  Big Data Stacks validation w/ iTest  How to tame the elephant?
Hadoop: Big Data Stacks validation w/ iTest How to tame the elephant?
Dmitri Shiryaev
 
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript librariesJazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Simon Willison
 
Complex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBoxComplex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBox
bobmcwhirter
 
Practical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.js
async_io
 
Treinamento frontend
Treinamento frontendTreinamento frontend
Treinamento frontend
Adrian Caetano
 
Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)
Mike West
 
Buildingsocialanalyticstoolwithmongodb
BuildingsocialanalyticstoolwithmongodbBuildingsocialanalyticstoolwithmongodb
Buildingsocialanalyticstoolwithmongodb
MongoDB APAC
 
node.js: Javascript's in your backend
node.js: Javascript's in your backendnode.js: Javascript's in your backend
node.js: Javascript's in your backend
David Padbury
 
Surge2012
Surge2012Surge2012
Surge2012
davidapacheco
 
XPages Blast - ILUG 2010
XPages Blast - ILUG 2010XPages Blast - ILUG 2010
XPages Blast - ILUG 2010
Tim Clark
 
Javascript why what and how
Javascript why what and howJavascript why what and how
Javascript why what and how
sureshpraja1234
 
Simpler Core Data with RubyMotion
Simpler Core Data with RubyMotionSimpler Core Data with RubyMotion
Simpler Core Data with RubyMotion
Stefan Haflidason
 
Advanced Node.JS Meetup
Advanced Node.JS MeetupAdvanced Node.JS Meetup
Advanced Node.JS Meetup
LINAGORA
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
Matthias Noback
 
node.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang Yoonnode.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang Yoon
Jesang Yoon
 
JavaScript Event Loop
JavaScript Event LoopJavaScript Event Loop
JavaScript Event Loop
Thomas Hunter II
 
Connecting to a REST API in iOS
Connecting to a REST API in iOSConnecting to a REST API in iOS
Connecting to a REST API in iOS
gillygize
 
Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0
Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0
Asfws 2014 slides why .net needs ma-cs and other serial(-ization) tales_v2.0
Cyber Security Alliance
 
The Theory Of The Dom
The Theory Of The DomThe Theory Of The Dom
The Theory Of The Dom
kaven yan
 
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
CocoaHeads PDX 2014 01 23 : CoreData and iCloud Improvements iOS7 / OSX Maver...
smn-automate
 
Hadoop: Big Data Stacks validation w/ iTest How to tame the elephant?
Hadoop:  Big Data Stacks validation w/ iTest  How to tame the elephant?Hadoop:  Big Data Stacks validation w/ iTest  How to tame the elephant?
Hadoop: Big Data Stacks validation w/ iTest How to tame the elephant?
Dmitri Shiryaev
 
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript librariesJazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Simon Willison
 
Complex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBoxComplex Made Simple: Sleep Better with TorqueBox
Complex Made Simple: Sleep Better with TorqueBox
bobmcwhirter
 
Practical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.jsPractical Use of MongoDB for Node.js
Practical Use of MongoDB for Node.js
async_io
 
Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)Intro to IndexedDB (Beta)
Intro to IndexedDB (Beta)
Mike West
 
Buildingsocialanalyticstoolwithmongodb
BuildingsocialanalyticstoolwithmongodbBuildingsocialanalyticstoolwithmongodb
Buildingsocialanalyticstoolwithmongodb
MongoDB APAC
 
node.js: Javascript's in your backend
node.js: Javascript's in your backendnode.js: Javascript's in your backend
node.js: Javascript's in your backend
David Padbury
 
XPages Blast - ILUG 2010
XPages Blast - ILUG 2010XPages Blast - ILUG 2010
XPages Blast - ILUG 2010
Tim Clark
 
Javascript why what and how
Javascript why what and howJavascript why what and how
Javascript why what and how
sureshpraja1234
 
Simpler Core Data with RubyMotion
Simpler Core Data with RubyMotionSimpler Core Data with RubyMotion
Simpler Core Data with RubyMotion
Stefan Haflidason
 
Advanced Node.JS Meetup
Advanced Node.JS MeetupAdvanced Node.JS Meetup
Advanced Node.JS Meetup
LINAGORA
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
Matthias Noback
 
node.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang Yoonnode.js 실무 - node js in practice by Jesang Yoon
node.js 실무 - node js in practice by Jesang Yoon
Jesang Yoon
 
Ad

More from Inferis (6)

Practical auto layout
Practical auto layoutPractical auto layout
Practical auto layout
Inferis
 
Communicating with GIFs
Communicating with GIFsCommunicating with GIFs
Communicating with GIFs
Inferis
 
Autolayout primer
Autolayout primerAutolayout primer
Autolayout primer
Inferis
 
Objective c runtime
Objective c runtimeObjective c runtime
Objective c runtime
Inferis
 
I Am A Switcher
I Am A SwitcherI Am A Switcher
I Am A Switcher
Inferis
 
Dynamic Silverlight
Dynamic SilverlightDynamic Silverlight
Dynamic Silverlight
Inferis
 
Practical auto layout
Practical auto layoutPractical auto layout
Practical auto layout
Inferis
 
Communicating with GIFs
Communicating with GIFsCommunicating with GIFs
Communicating with GIFs
Inferis
 
Autolayout primer
Autolayout primerAutolayout primer
Autolayout primer
Inferis
 
Objective c runtime
Objective c runtimeObjective c runtime
Objective c runtime
Inferis
 
I Am A Switcher
I Am A SwitcherI Am A Switcher
I Am A Switcher
Inferis
 
Dynamic Silverlight
Dynamic SilverlightDynamic Silverlight
Dynamic Silverlight
Inferis
 
Ad

Recently uploaded (20)

Rusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond SparkRusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond Spark
carlyakerly1
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath MaestroDev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
UiPathCommunity
 
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx
Samuele Fogagnolo
 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Semantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AISemantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AI
artmondano
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 
HCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser EnvironmentsHCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser Environments
panagenda
 
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdfSAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
Precisely
 
Rusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond SparkRusty Waters: Elevating Lakehouses Beyond Spark
Rusty Waters: Elevating Lakehouses Beyond Spark
carlyakerly1
 
Build Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For DevsBuild Your Own Copilot & Agents For Devs
Build Your Own Copilot & Agents For Devs
Brian McKeiver
 
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath MaestroDev Dives: Automate and orchestrate your processes with UiPath Maestro
Dev Dives: Automate and orchestrate your processes with UiPath Maestro
UiPathCommunity
 
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes Partner Innovation Updates for May 2025
ThousandEyes
 
How analogue intelligence complements AI
How analogue intelligence complements AIHow analogue intelligence complements AI
How analogue intelligence complements AI
Paul Rowe
 
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep DiveDesigning Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
Designing Low-Latency Systems with Rust and ScyllaDB: An Architectural Deep Dive
ScyllaDB
 
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptxDevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
DevOpsDays Atlanta 2025 - Building 10x Development Organizations.pptx
Justin Reock
 
2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx2025-05-Q4-2024-Investor-Presentation.pptx
2025-05-Q4-2024-Investor-Presentation.pptx
Samuele Fogagnolo
 
TrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business ConsultingTrsLabs - Fintech Product & Business Consulting
TrsLabs - Fintech Product & Business Consulting
Trs Labs
 
Cyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of securityCyber Awareness overview for 2025 month of security
Cyber Awareness overview for 2025 month of security
riccardosl1
 
Mobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi ArabiaMobile App Development Company in Saudi Arabia
Mobile App Development Company in Saudi Arabia
Steve Jonas
 
Electronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploitElectronic_Mail_Attacks-1-35.pdf by xploit
Electronic_Mail_Attacks-1-35.pdf by xploit
niftliyevhuseyn
 
Semantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AISemantic Cultivators : The Critical Future Role to Enable AI
Semantic Cultivators : The Critical Future Role to Enable AI
artmondano
 
Heap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and DeletionHeap, Types of Heap, Insertion and Deletion
Heap, Types of Heap, Insertion and Deletion
Jaydeep Kale
 
Technology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data AnalyticsTechnology Trends in 2025: AI and Big Data Analytics
Technology Trends in 2025: AI and Big Data Analytics
InData Labs
 
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
#StandardsGoals for 2025: Standards & certification roundup - Tech Forum 2025
BookNet Canada
 
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
AI EngineHost Review: Revolutionary USA Datacenter-Based Hosting with NVIDIA ...
SOFTTECHHUB
 
Drupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy ConsumptionDrupalcamp Finland – Measuring Front-end Energy Consumption
Drupalcamp Finland – Measuring Front-end Energy Consumption
Exove
 
HCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser EnvironmentsHCL Nomad Web – Best Practices and Managing Multiuser Environments
HCL Nomad Web – Best Practices and Managing Multiuser Environments
panagenda
 
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdfSAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
SAP Modernization: Maximizing the Value of Your SAP S/4HANA Migration.pdf
Precisely
 

Adventures in Multithreaded Core Data

  • 1. Adventures in Multithreaded Core Data CocoaheadsBE - Zoersel, 2012-09-24
  • 5. I love... ‣ ... my wife ‣ ... my 4 kids ‣ ... to code ‣ ... to play a game of squash ‣ ... good beer
  • 6. I open sourced... ... some code: ‣ IIViewDeckController: “An implementation of the sliding functionality found in the Path 2.0 or Facebook iOS apps.” ‣ IIDateExtensions ‣ IIPopoverStatusItem See: http://github.com/inferis
  • 7. I made... ... some apps: Butane Drash http://getbutane.com http://dra.sh Hi, @10to1!
  • 8. Butane Campfire client for iOS ‣ Official Campfire client kinda sucks, so we rolled our own ‣ Somewhat concurrent app ‣ Uses Core Data ‣ Together with 10to1
  • 9. This presentation is about what I learned while coding Butane.
  • 11. Agenda ‣ Core Data Primer ‣ MagicalRecord ‣ Concurrency problems ‣ Concurrency solutions
  • 13. What is: Core Data? ‣ Per the documentation: ‣ The  Core  Data  framework  provides   generalized  and  automated  solutions   to  common  tasks  associated  with   object  life-­‐cycle  and  object  graph   management,  including  persistence. http://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/CoreData/Articles/cdTechnologyOverview.html#//apple_ref/doc/uid/TP40009296-SW1
  • 15. What isn’t: Core Data? ‣ It’s not an RDBMS. ‣ If you want a database and SQL, use Sqlite:
  • 16. What isn’t: Core Data? ‣ It’s not just an ORM (Object Relational Mapper) ‣ It may look like there’s SQL under the hood, but that’s not necessarily the case.
  • 17. So, what is it then? Core Data provides: ‣ persistence ‣ change tracking ‣ relations (object graph) ‣ lazy loading (“faulting”) ‣ validation ‣ works well with Cocoa (KVO, KVC)
  • 18. Basically: ‣ A system to store data ‣ Persistence agnostic (local storage, iCloud, AFIncrementalStore, ...) ‣ No need to write SQL to query ‣ You can keep to Objective-C
  • 19. Your tools: ‣ NSPersistentStore ‣ NSManagedObjectContext ‣ NSManagedObject ‣ NSManagedObjectID   ‣ NSFetchRequest ‣ NSEntityDescription ‣ NSPredicate ‣ NSSortDescription
  • 20. A picture says a 1000 words...
  • 22. MagicalRecord ‣ Writing Core Data code is tedious. ‣ You need quite a bit of boilerplate code to do something simple: NSManagedObjectContext  *moc  =  [self  managedObjectContext]; NSEntityDescription  *entityDescription  =  [NSEntityDescription  entityForName:@"Employee"  inManagedObjectContext:moc]; NSFetchRequest  *request  =  [NSFetchRequest  new]; [request  setEntity:entityDescription];   NSSortDescriptor  *sortDescriptor  =  [[NSSortDescriptor  alloc]  initWithKey:@"firstName"  ascending:YES]; [request  setSortDescriptors:@[sortDescriptor]];   NSError  *error; NSArray  *array  =  [moc  executeFetchRequest:request  error:&error]; if  (array) {   //  display  items  (eg  in  table  view) } else  {        //  Deal  with  error... }
  • 23. MagicalRecord ‣ MagicalRecord tries to solve this. ‣ = ActiveRecord pattern for Core Data. ‣ Encapsulates the tediousness of plain Core Data code.
  • 24. MagicalRecord ‣ Writing MagicalRecord enable code is tedious no more: ‣ That same example is now this: NSManagedObjectContext  *moc  =  [self  managedObjectContext]; NSArray  *array  =  [Employee  MR_findAllSortedBy:@"firstname"  ascending:YES  inContext:context]; if  (array) {   //  display  items  (eg  in  table  view) } else  {        //  Deal  with  error... }
  • 27. MagicalRecord + write less code + your code becomes more readable + good for apps requiring simple storage scenarios (=most apps, probably) + hides complexity - hides complexity - easy to start, but diving deeper becomes harder - uses defaults that are suboptimal in a multithreaded app - concurrency errors and issues are subtle
  • 28. MagicalRecord ‣ used MagicalRecord from the start ‣ Took me a while to find out the problems I was having were related to the complexity hiding ‣ The defaults are okay only for so much app complexity
  • 29. MagicalRecord ‣ That said: Magical Record is great. ‣ It will speed up your Core Data development by several factors. ‣ Also: take a look at mogenerator: ‣ http://rentzsch.github.com/mogenerator/ ‣ or: brew  install  mogenerator
  • 30. MagicalRecord ‣ So I threw it out.
  • 31. MagicalRecord ‣ So I threw it out. ‣ But not completely.
  • 32. MagicalRecord ‣ So I threw it out. ‣ But not completely. ‣ More about that later.
  • 33. The problems described hereafter only apply to the persistent stores with external backing (for example: sqlite).
  • 36. Problems? ‣ Core Data Objects are not thread safe.
  • 37. Problems? ‣ Core Data Objects are not thread safe. ‣ In essence: you can’t share them across threads (except for NSManagedObjectID).
  • 38. Problems? ‣ Core Data Objects are not thread safe. ‣ In essence: you can’t share them across threads (except for NSManagedObjectID). ‣ Core Data locks objects, even for read operations.
  • 39. Object storage is locked for read operations, too ‣ Objects used to power the UI must be fetched on the UI thread. ‣ Heavy/complex fetch requests (queries) block the UI thread while fetching the objects. You don’t want that.
  • 40. Objects aren’t supposed to be shared between threads ‣ The NSManagedObjectContext “locks” an object when you read one of its properties. ‣ This can cause a deadlock when you do access the same data from 2 threads. ‣ Reason: faulting support can change the object even while just reading from it. ‣ You can’t turn it off.
  • 42. Luckily, we can fix or workaround these problems.
  • 44. Keep to your thread
  • 45. Keep to your thread ‣ pre-iOS5: use thread confinement
  • 46. Keep to your thread ‣ pre-iOS5: use thread confinement ‣ iOS5 and later: use nested contexts
  • 47. Thread confinement ‣ In essence: keep an NSManagedObjectContext per thread ‣ Be very careful when going from one thread to another. ‣ MagicalRecord tries to hide this from you: ‣ It automatically provides a context for each thread ‣ This is a bit counterintuitive since you start mixing objects across threads quite easily.
  • 48. Thread confinement Image source: Cocoanetics
  • 49. Nested contexts ‣ Introduced in iOS5 ‣ Uses Grand Central Dispatch and dispatch queues ‣ Core Data manages threading for you ‣ Better than thread confinement ‣ more straightforward ‣ more flexible ‣ MagicalRecord hides this from you, too. ‣ Automatically switches to dispatch queues on iOS5 even though the API remains the same.
  • 50. Nested contexts Image source: Cocoanetics
  • 51. Nested contexts ‣ NSManagedObjectContext = cheap ‣ You can nest contexts ‣ Each context has its private dispatch queue ‣ No manual thread synchronization necessary
  • 52. Queue types ‣ NSConfinementConcurrencyType ‣ The old way (thread confinement) ‣ NSPrivateQueueConcurrencyType ‣ The context has its own private dispatch queue ‣ NSMainQueueConcurrencyType ‣ The context is associated with the main queue (or runloop, or UI thread) parentMoc  =  [[NSManagedObjectContext  alloc]  initWithConcurrencyType:NSMainQueueConcurrencyType]; [parentMoc  setPersistentStoreCoordinator:coordinator]; moc  =  [[NSManagedObjectContext  alloc]  initWithConcurrencyType:NSPrivateQueueConcurrencyType]; moc.parentContext  =  parentMoc;
  • 53. Thread safe? ‣ performBlock:   performBlockAndWait: ‣ Run a block you provide on the queue associated with the context. ‣ Object access in the block is thread safe [context  performBlockAndWait:^{        for  (Room*  room  in  [Room  findAllInContext:context])  {                room.joinedUsers  =  [NSSet  set];                room.knowsAboutJoinedUsersValue  =  NO;                room.unreadCountValue  =  0;                room.status  =  @"";        }        NSError*  error  =  nil;        [context  save:&error]; }];
  • 54. performBlock, and wait -­‐  (void)performBlock:(void  (^)())block; ‣ executes the block on the context dispatch queue as soon as possible ‣ nonblocking call ‣ code will not execute immediately -­‐  (void)performBlockAndWait:(void  (^)())block; ‣ executes the block on the context dispatch queue immediately ‣ blocks the current execution until block is done ‣ can cause a deadlock (if you’re already running code on the same queue)
  • 55. When to use what? ‣ performBlock: ‣ For actions which are “on their own” ‣ Consider the code in the block a Unit Of Work ‣ Best for save operations ‣ Useful for long fetches (use callbacks) ‣ performBlockAndWait: ‣ When you need stuff immediately ‣ Good for small fetches or “standalone” saves
  • 56. How is this better than thread confinement? ‣ No manual thread handling, Core Data handles it for you. ‣ More flexible: as long as you access managed objects in the correct context using performBlock: you’re pretty safe ‣ also applies to the main/UI thread! (unless you’re sure you’re on the main thread)
  • 57. Saving nested contexts ‣ Saves are only persisted one level deep. ‣ Parent contexts don’t pull changes from child contexts. ‣ Child contexts don’t see changes by parent contexts. ‣ Make them plenty and short-lived
  • 58. How to nest contexts ‣ 2 approaches: ‣ root context = NSMainQueueConcurrencyType ‣ root context = NSPrivateQueueConcurrencyType
  • 59. Root = Main ‣ Many child contents with private queues ‣ Root context on main queue ‣ Actual persistence happens on main queue, could block the UI Image source: Cocoanetics
  • 60. Root = Private ‣ Root context with private queue ‣ Many child contents with private queues ‣ context on main queue is child of root ‣ Actual persistence happens in background (does not block the UI) Image source: Cocoanetics
  • 61. What problems did we have again?
  • 62. What problems did we have again? ‣ No sharing of NSManagedObjects between threads.
  • 63. What problems did we have again? ‣ No sharing of NSManagedObjects between threads. ‣ Context locking
  • 64. Sharing: solution ‣ Pass only NSManagedObjectIDs to other threads, not objects. ‣ Refetch the object on a different thread or queue to work with it. ‣ Don’t forget to save the ‘original’ object first before working with it on the second thread or queue.
  • 65. Complex queries ‣ Use the same technique for complex or large queries. 1. do the heavy lifting in the background 2. pass list of NSManagedObjectIDs to another thread (e.g. UI thread). 3. load objects as faults, and let Core Data fault them in when you need them (e.g. when accessing a property) ‣ That’s lot of requests, but this is actually more performant and desirable in most cases.
  • 66. Locking: solution ‣ Use child contexts with their own dispatch queues. ‣ Use: performBlock: and performBlockAndWait:  carefully. ‣ Deadlocks still possible, especially with performBlockAndWait:
  • 67. A word about NSManagedObjectIDs ‣ Two types of IDs: ‣ temporary ‣ when the object hasn’t been persisted to a store ‣ permanent ‣ when the object has been persisted to a store
  • 68. A word about NSManagedObjectIDs ‣ Subtle bug: temporary IDs from a non-root context don’t get updated to permanent IDs when saving in the root context ‣ The object is saved just fine, but the ID is not updated correctly. ‣ When passing these around to other contexts after saving: you won’t find the object in another child context!
  • 69. A word about NSManagedObjectIDs ‣ To the rescue: -­‐  (BOOL)obtainPermanentIDsForObjects: (NSArray  *)objects  error:(NSError   **)error;
  • 70. A word about NSManagedObjectIDs -­‐  (BOOL)obtainPermanentIDsForObjects:(NSArray   *)objects  error:(NSError  **)error; ‣ Transforms objects with temporary IDs to permanent IDs (through the persistent store of the root context). ‣ Do this when creating a managed object and you’re safe. ‣ Obtaining permanentIDs is batched, so the performance hit is not that high
  • 71. MagicalRecord ‣ I still use MagicalRecord: ‣ Reduced form: no more “automatic” context handling --> dangerous! ‣ Added some extra sauce to work with the nested contexts. ‣ The methods MR supplies still allow for a speedup when coding.
  • 72. Useful References ‣ Nested context release notes: http://developer.apple.com/library/mac/#releasenotes/ DataManagement/RN-CoreData/_index.html ‣ Magical Record: https://github.com/magicalpanda/MagicalRecord ‣ Mogenerator: http://rentzsch.github.com/mogenerator/ ‣ A good read on Cocoanetics: http://www.cocoanetics.com/2012/07/multi-context-coredata/ ‣ Core data programming guide: http://developer.apple.com/library/mac/#documentation/ cocoa/Conceptual/CoreData/cdProgrammingGuide.html ‣ Butane: http://getbutane.com
  • 73. Thanks for listening. Questions? Contact me: Twitter: @inferis App.Net: @inferis E-mail: [email protected] vCard: http://inferis.org