1

I have defined a Core Data for my project and implemented an ENtity:attribute called isRealEntry.

@interface FTRecord : NSManagedObject

@property (nonatomic) NSTimeInterval lastUpdated;
@property (nonatomic) BOOL isRealEntry;

@end

Now when I save the context (NSManagedObjectContext *context;)

NSError *error = nil;
BOOL successful = [context save:&error];

I would like to save only those entities that have a true isRealEntry, otherwise the entry shall be ignored or undone.

How can I achieve this?

Update:

At first I found Martin's solution very promising. However I get a very nasty side effect when I save my data upon entering background:

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    [[FTRecordStore sharedStore] saveChanges];
}

When I resume the app, all the previous deleted records aren't gone for real but flagged to be deleted. The array still seems to have all of them (real or unreal in my case). The cells go completely nuts and show empty for all records.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    FTRecord *record = [[[FTRecordStore sharedStore] getAllRecords] objectAtIndex:[indexPath row]];

FTRecordCellView *cell = [tableView dequeueReusableCellWithIdentifier:@"FTRecordCellView"];

    [[cell notesLabel] setText:[record notes]];

return cell;
}

I am not sure how to solve this. My Store is a singleton. getAllRecords determines above the content for each cell. Hence I need to have the same value for getAllRecords as also in the tableView, or it would crash.

The other suggested solution with two sources one in memory and in db seems also not to be possible, how do I feed one TableView with two sources?

Update 2:

I had an embarassing oversight. Deleting the record from context is not enough. I also had to delete it from the array.

[allRecords removeObjectIdenticalTo:record];

Therefore I take it back. Martin's solution works perfect. However I am still curious to know if a UITableView can indeed be driven from two sources (db/memory) as suggested in teh other solution. Thanks

Houman
  • 64,245
  • 87
  • 278
  • 460

3 Answers3

2

I've had to do something similar to this before and the way I approached it was to have a seperate managed object context for items that I was going to persist, and another for items that were staying in memory only.

I went about it by having a seperate persistent store cordinator as well as a separate managed object context that is in memory only, so when items are saved into it, they don't get persisted to the database with what you described as real items.

You can create an in memeory persistent store coordinator like this:

inMemoryPersistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

[inMemoryPersistentStoreCoordinator addPersistentStoreWithType:NSInMemoryStoreType configuration: nil URL: nil options: nil error: &error];

If you want to change non real items into real items, you can copy them into the other managed object context which will persist the items to the database when it's saved.

The obvious issue here is that searching is done on a single managed object context so if you hoped to search through persisted and in memory objects, then you would need to do something more along the lines of what Arkadiusz suggested in his answer.

Duncan
  • 173
  • 1
  • 7
  • 1
    +1. You can even use *one* context, *one* persistent store coordinator, and *two* stores (sqlite + in memory), and then associate objects with one store or the other: http://stackoverflow.com/a/14005159/1187415. - Obviously, I had forgotten my own answer from one year ago :-) – Martin R Oct 11 '13 at 17:59
  • Thanks Martin, nice addition! I didn't realise you could do that – Duncan Oct 11 '13 at 19:26
  • While this is a valid solution, I believe Martin's other solution, which I accepted as an answer is less complicated. Overriding a `WillSave` is far more feasible than controlling two sets of storage. :) – Houman Oct 12 '13 at 11:49
0

I don't believe there is a built in way to do this. I believe you would either have to delete them before saving or write cleanup code to find and delete them later.

Alex
  • 1,625
  • 12
  • 18
0

Saving a managed object contexts saves all changes make to that context. You cannot exclude some objects from the save operation.

To undo all changes to the "unreal" objects, you could implement the willSave method of the NSManagedObject subclass:

- (void)willSave
{
    if (![self.isRealEntry boolValue]) {
        if (self.isInserted) {
            // Object was inserted, remove it again:
            [self.managedObjectContext deleteObject:self];
        } else if (self.isUpdated) {
            // Object was modified, undo all changes:
            [self.managedObjectContext refreshObject:self mergeChanges:NO];
        }
    }
}

(I never did this in a real project, but I built a small test app and it seems to work.)

Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Sorry Martin, as you warned, this caused some issues, which I have given in my update. Do you have any other idea regarding UITableView sharing two sources (Memory/db)? – Houman Oct 12 '13 at 21:13
  • @Kave: Have a look at http://stackoverflow.com/questions/14004055/how-to-use-core-data-models-without-saving-them/14005159#14005159. That is similar to Duncan's suggestion, but uses only one managed object context with two stores: The "real" objects are assigned to the SQLite store, and the "unreal" objects are assigned to the Memory store. – Martin R Oct 12 '13 at 21:24