## Context
I've a simple Core Data stack: `MainQueueMOC -> PrivateBackgroundMOC -> PersistentStoreCoordinator` that is managed by my `TTPersistenceManager` that looks like this:
typedef NS_ENUM(NSInteger, TTPersistenceType) {
TTPersistenceTypeInMemory,
TTPersistenceTypeSQLite
};
@interface TTPersistenceManager : NSObject
@property (strong, nonatomic, readonly) NSManagedObjectContext *managedObjectContext; // this is the MainQueueMOC
- (id)initWithPersistenceType:(TTPersistenceType)persistenceType;
- (void)initializeCoreData;
- (void)save;
- (void)persist;Currently we only use the in memory store.
It is inspired by this article from Marcus Zarra. So the MainQueueMOC is the single source of truth, and the PrivateBackgroundMOC is only used to save to the store in background, and it is never publicly exposed. If you read the article you'll notice that I added a method called `persist`, the difference between `save` and `persist` is:
- `save`, saves the MainQueueMOC using `performBlockAndWait`
- `persist`, saves the MainQueueMOC using `performBlockAndWait` and the PrivateBackgroundMOC using `performBlock`
I did mostly because of these two paragraphs:
>As a rule, any time we are leaving the application we want to call save on the persistence controller. This guarantees that if we get killed while paused, we will not be losing data.
>In most cases this is the only place you need to call save on the main and private contexts.
So `save` is the method that saves the single source of truth and we call it after any change to a managed object, while `persist` is only called on the app delegate when the goes to background or is about to be terminated to save all the changes to the store.\
This works fine except for the following problem.
## The Problem
We have a `NSFetchedResultsController` with a predicate like this:
item.kind = "relationship" AND item.relationship.archived == NOWe don't show items that are associated with an archived relationship. The user can swipe on the row to Archive it, which that changes `relationship.archived = @YES`, calls `[TTPersistenceManager save]`, and refetch the `NSFetchedResultsController` and that item disappear from the list. This works.
Until we enter background for the first time.
- (void)applicationDidEnterBackground:(UIApplication *)application {
[self.persistenceController persist];
}After calling `persist`, if a user swipes to Archive the item does not disappear from the list.
relationship.archived = @YES; // item at index 0 is associated with this object
[self.persistenceManager save];
[self.fetchedResultsController performFetch:&error]; // Works, no error
item = [[self.fetchedResultsController] fetchedObjects] firstObject];
NSLog(@"item is archived %d", item.relationship.archived);
// prints: item is archived 1The `relationship` object has its `archived` property set to `YES` but the fetch still returns it.
## The Possible Solutions
I've found two possible solutions. But I want to choose the more correct one, the one that will work as expected in all cases regardless if we using in-memory store or sqlite.
1. Add a `updatedAt` attribute to `item` that we set the current date every time we update `relationship`:
relationship.item.updatedAt = [NSDate date];
relationship.archived = @YES;
[self.persistenceManager save];2. Always call `persist` instead of `save`:
relationship.archived = @YES;
[self.persistenceManager persist];- What is the correct approach?
- Is my assumption that we only to save the MOC connected to the persistent store when going into background?
- Why does adding an attribute to `item` that is not even used in the predicate works?