Reputation: 13135
Consider the following correlation between dictionary objects in a feed and sorted entities in core data:
Feed CoreData
---- --------
A A
B B
C C
D D
As I'm enumerating the feed, I check if A's [stringForKey:@"name"]
isEqualTo A.name
in the entity. If it's a match, I update the entity. If it's not, I insert a new entity into CoreData.
This works fine for updating and inserting, but not for deletion. Consider that object C is removed from the feed:
Feed CoreData
---- --------
A A
B B
D C
D
When I get to "D" in the feed, it will see that object "C" in CoreData is not a match and create a new object D. So I have two problems now: I have two "D" objects, and object "C" does not get removed from CoreData.
So while I want to end up with this:
Feed CoreData
---- --------
A A
B B
D D
What I currently get is this:
Feed CoreData
---- --------
A A
B B
D C
D
D
This must be a common issue so I'm wondering what the best practice is here for determining when to remove entities from Core Data.
Upvotes: 1
Views: 555
Reputation: 540075
As it seems, you already have an array of Feed objects and an array of CoreData objects, both sorted by the same attribute "name" in increasing order.
You can update/insert/delete the CoreData objects from the Feed objects with a single loop over both arrays using two independent pointers into the arrays.
The pseudo-code looks like this:
i1 = 0; // pointer into Feed array
i2 = 0; // pointer into CD (CoreData objects) array
while (i1 < Feed.count && i2 < CD.count) {
if (Feed[i1].name < CD[i2].name) {
// Feed[i1] is not in CD array
"Insert Feed[i1] as new Core Data object"
i1++;
} else if (Feed[i1].name > CD[i2].name) {
// CD[i2].name is not in Feed array
"Delete CD[i2] from Core Data"
i2++;
} else {
"Update CD[i2] from Feed[i1]"
i1++, i2++;
}
}
// Add remaining objects from Feed array:
while (i1 < Feed.count) {
"Insert Feed[i1] as new Core Data object"
i1++;
}
// Remove remaining Core Data objects
while (i2 < CD.count) {
"Delete CD[i2] from Core Data"
i2++;
}
In your example:
Feed CoreData ---- -------- i1->A i2->A same name, CoreData object is updated, i1++, i2++ B B D C D
Feed CoreData ---- -------- A A i1->B i2->B same name, CoreData object is updated, i1++, i2++ D C D
Feed CoreData ---- -------- A A B B i1->D i2->C "D" > "C", CoreData object is deleted, i2++ D
Feed CoreData ---- -------- A A B B i1->D C i2->D same name, CoreData object is updated, i1++, i2++
Upvotes: 1
Reputation: 314
This is what I do when I loop through items to determine whether to update, insert, or delete:
-(void)updateWithJSON:(id)JSON
{
//Get an array of all related managed objects
NSMutableArray *allContacts = [[NSMutableArray alloc] initWithArray:[self getAllContacts]];
//Loop through each object downloaded from the server
for (NSDictionary *objectInfo in [JSON objectForKey:@"Contacts"])
{
NSString *objectKey = [objectInfo objectForKey:@"BackendID"];
//Get the managed object for the objectKey
Contact *contact = [[allContacts filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"backendID == %@", objectKey]] lastObject];
//If the object is nil, then insert the object
if (contact == nil)
{
NSLog(@"Object with key %@ is new.", objectKey);
contact = [[Contact alloc] initWithEntity:[NSEntityDescription entityForName:@"Contact" inManagedObjectContext:self.managedObjectContext] insertIntoManagedObjectContext:self.managedObjectContext];
contact.backendID = objectKey;
}
//Assign property values
contact.firstName = [objectInfo objectForKey:@"FirstName"];
contact.lastName = [objectInfo objectForKey:@"LastName"];
contact.jobTitle = [objectInfo objectForKey:@"JobTitle"];
contact.department = [objectInfo objectForKey:@"Department"];
contact.email = [objectInfo objectForKey:@"Email"];
contact.fax = [objectInfo objectForKey:@"Fax"];
contact.primaryPhone = [objectInfo objectForKey:@"PrimaryPhone"];
contact.secondaryPhone = [objectInfo objectForKey:@"SecondaryPhone"];
//Remove the object from the array of all the objects
if ([allContacts containsObject:contact])
[allContacts removeObject:contact];
}
//Delete any objects that still remain in the array (means they were deleted server-side
for (Contact *contact in allContacts) {
NSLog(@"Removing Contact with key %@", contact.backendID);
[self.managedObjectContext deleteObject:contact];
}
NSError *error = nil;
[self.managedObjectContext processPendingChanges];
[self.managedObjectContext save:&error];
if (error)
NSLog(@"Error Saving Contacts: %@", error.localizedDescription);
}
Upvotes: 2