Domanda

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.

È stato utile?

Soluzione

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);
}

Altri suggerimenti

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++
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top