title: Getting and using NSManagedObject in different threads
body: <p>I have problem with architecting my code.
  I have <code>view</code> that create and depend on <code>model</code> class. Model class is responsible for all calculations and logic. This mean that it has a lot of things to calculate, and getting object from Core data.</p>
  
  <p><a href="https://i.stack.imgur.com/ZU0oe.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ZU0oe.png" alt="enter image description here"></a></p>
  
  <p>Regarding <a href="https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/Concurrency.html" rel="nofollow noreferrer">enter link description here</a>, every NSManagedObject that is obtained in one thread, need to be used in same thread.</p>
  
  <p>My problem is that on create object need to be obtained in different thread, because it take some time to build model, but after this, I need to obtain object and they properties in main thread from View (for example in cellForIndex...)</p>
  
  <p>I know, I am not the only one with this design. How others solve this problem?</p>
  
  <hr>
  
  <p>EDIT : </p>
  
  <p>To concrete this with code.</p>
  
  <p>Let say we have <code>UIView</code> object <code>MyUIView</code> and model object <code>Model</code></p>
  
  <blockquote>
    <p>MyUIView</p>
  </blockquote>
  
  <pre><code> @interface MyUIView ()
  
   @property(nonatomic) Model * model;
  
   @end
  
   @implementation MyUIView
  
   - (void) createModel
   {
       // privateManagerContext is context manager created with 
       // NSPrivateQueueConcurrencyType, connected to persistent store
       // and sync with "main thread" manager context with 
       // NSManagedObjectContextDidSaveNotification and NSManagedObjectContextDidSaveNotification
  
       [self.model createWithManagadContext:privateManagerContext];
   }
  
   // ASSUME THAT THIS CODE IS CALLED AFTER 
   - (void) getNumberOfSomeProperties
   {
      int number  = [self.model getNumberOfProperties];
   }
  
   - (void) getProperties
   {
      NSArray *array = [self.model properties]
   }
  
   // OR WE HAVE TO TRIGGERED SOME LONG CALCULATION
  
   - (void) triggerLongCalculation
   {
       [self.model longCalculation];
   }
  
   - (void) afterNotifyModelIsCompletedCalculating
   {
       [self doSomeWork];
       [self getProperties];
       ....
   }
   @end
  </code></pre>
  
  <blockquote>
    <p>Model</p>
  </blockquote>
  
  <pre><code> @interface Model ()
  
   @property(nonatomic) NSArray * cashedProperties;
  
   @end
  
   @implementation MyUIView
  
   - (void) createWithManagadContext:(NSManagedObjectContext *) privateManagerContext
   {
       dispatch_async(self.model_queue, ^(void){
  
           // Here we fetch objects and do some calculations
           [self populateModel];
  
           /// Model is complete
           [Notifications notifyModelIsCompletedCreating:self];
       });
   }
  
  
   - (void) longCalculation
   {
       dispatch_async(self.model_queue, ^(void){
          // NO CORE DATA FETCH INVOLVED
          [Notifications notifyModelIsCompletedCalculating:self];
      });
   }
  
   - (int) getNumberOfProperties
   {
      return self.cashedProperties.count;
   }
  
   - (NSArray) properties
   {
      NSMutableArray * a = [[NSMutableArray alloc]init];
      for (Property * p in self.cashedProperties) {
          [a addObject:p.name];
      }
  
      return a;
   }
  
   @end
  </code></pre>
  
  <p>So in this hypothetical classes, how would you handle all NSManagedObject and NSManagedObjectContext ?</p>
  
  <p>EDIT 2 :</p>
  
  <hr>
  
  <p>I am using pattern where I create two managed object context in appdelegate, one private and one main, and create sync between them. </p>
  
  <pre><code>- (NSManagedObjectContext *)managedObjectContext
  {
      if (__managedObjectContext != nil) {
          return __managedObjectContext;
      }
  
      NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
      if (coordinator != nil) {
          __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
          [__managedObjectContext setPersistentStoreCoordinator:coordinator];
      }
      return __managedObjectContext;
  }
  
  - (NSManagedObjectContext * ) privateQueueContext
  {
      if (_privateQueueContext != nil) {
          return _privateQueueContext;
      }
  
      NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
      if (coordinator != nil) {
          _privateQueueContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
          [_privateQueueContext setPersistentStoreCoordinator:coordinator];
      }
      return _privateQueueContext;
  }
  
  
  - (id)init
  {
      self = [super init];
      if (self) {
          [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(contextDidSavePrivateQueueContext:)
                                                   name:NSManagedObjectContextDidSaveNotification
                                                 object:[self privateQueueContext]];
          [[NSNotificationCenter defaultCenter] addObserver:self
                                               selector:@selector(contextDidSaveMainQueueContext:)
                                                   name:NSManagedObjectContextDidSaveNotification
                                                     object:[self managedObjectContext]];
      }
      return self;
  }
  
  #pragma mark - Notifications
  
  - (void)contextDidSavePrivateQueueContext:(NSNotification *)notification
  {
      @synchronized(self) {
          [self.managedObjectContext performBlock:^{
  
              NSArray* objects = [notification.userInfo valueForKey:NSUpdatedObjectsKey];
              for (NSManagedObject* obj in objects) {
                  NSManagedObject* mainThreadObject = [self.managedObjectContext objectWithID:obj.objectID];
                  [mainThreadObject willAccessValueForKey:nil];
              }
  
              [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
          }];
      }
  }
  
  - (void)contextDidSaveMainQueueContext:(NSNotification *)notification
  {
      @synchronized(self) {
          [self.privateQueueContext performBlock:^{
  
              NSArray* objects = [notification.userInfo valueForKey:NSUpdatedObjectsKey];
              for (NSManagedObject* obj in objects) {
                  NSManagedObject* mainThreadObject = [self.privateQueueContext objectWithID:obj.objectID];
                  [mainThreadObject willAccessValueForKey:nil];
              }
  
              [self.privateQueueContext mergeChangesFromContextDidSaveNotification:notification];
          }];
      }
  }
  </code></pre>