NSFetchedResultsController doesn't show updates from a different context

前端 未结 2 522
无人及你
无人及你 2020-12-28 15:32

I have an NSFetchedResultsController and a few operations updates managed objects on separate threads via NSOperationQueue.

The FRC (with i

相关标签:
2条回答
  • 2020-12-28 16:03

    I just had the same problem, which I solved with parent/child contexts. Here is the problem I had.

    I was updating my Core Data object graph in a background thread which had its own managedObjectContext (which is mandatory), and my fetchedResultsController was not able to pick up the changes done to the database.

    After I solved it I took some notes:

    ManagedObjectContexts are not thread safe, which means that a managedObjectContext cannot be shared with other threads. If a thread needs to use a managedObjectContext, then it will initialize its own managedObjectContext.

    To initialize a managedObjectContext there are two ways:

    • alloc/init then set its persistentStoreCoordinator property

    • alloc/init then set a parentContext property instead of a persistentStoreCoordinator property

    note: one cannot set both the persistentStoreCoordinator and the parentContext property of a managedObjectContext.

    Using parent/child contexts is needed when the a context is run on a background thread that is "linked to controllers and UI objects that are required to be used only on the main thread"(core data documentation).

    Here are the requirements needed for the parent/child contexts:

    • the parent context lives in the main thread

    • the child context lives in the background thread

    • both contexts need to be initialized with an initWithConcurrencyType:NSMainQueueConcurrencyType method.

    • when the batch of changes has been done in the child context, both contexts need to perform a save operation. These save operations need to be nested in performBlock methods, i.e:

      childContext performBlock:^{
          [childContext save:nil];
          [self.parentContext performBlock:^{
              [self.parentContext save:nil];                
          }];
      }];
      

    EDIT: The code above is actually a bad idea for 2 reasons:

    1) It works without saving the parent context.

    2) The main thread is blocked if the parent context runs on it.

    I hope it helped !

    EDIT: Here is a stackoverflow thread which helped me greatly: Does a Core Data parent ManagedObjectContext need to share a concurrency type with the child context?

    0 讨论(0)
  • 2020-12-28 16:18

    You have the basic idea, so there is probably a bug somewhere in your code...

    Double check that you are properly registering to receive the notification from the background MOC.

    Register to receive all notifications from all objects. In that method, log the event, and all its data. When the object is a MOC, dump all its properties (especially the lists of registered, inserted, updated, and deleted objects).

    Put a log statement right before and after the save call, and in the notification handler for merging the notification.

    Also, you omitted a lot of code so it's hard to know what you are actually doing, but the code sample you included looks like it is hard setting isSync to YES for all objects being loaded, but your fetch request only wants those with isSync set to NO. None of those new objects will pass that predicate.

    Finally, double check your model definition and make sure you are using the right number type. This can be a big source of problems.

    EDIT

    Oh yeah, I forgot... your fetch request does not have a sort descriptor. When you create a FRC, your fetch request must contain at least one sort descriptor... if you have multiple sections, the first sort descriptor is used to group the objects into sections.

    To follow up on Alexsander's comment... I alluded to it at the beginning of my post, but you certainly do not want to listen to notifications from a MOC unless it is well known as one of yours (unless, of course, you are just logging for debugging purposes). You should know about the MOC you are using.

    Furthermore, I would suggest using parent/child MOCs for this type of processing, but what you are doing should work if done properly.

    Parent (private concurrency type) Main (main concurrency type)

    Then, with your background MOCs, just have them set the main moc as their parent. When they save, their objects get injected directly into the main MOC. The main MOC can then issues saves at later times to put them onto disk.

    Or, you can parent you background MOC to the "parent" and then the "main" MOC can just reissue the fetch to get the data from the parent.

    0 讨论(0)
提交回复
热议问题