Say you have a one-to-many relationship (modeled via Core Data) between something like a tweet and a bunch of photos:
@implementation Tweet
- (void)updateWithDictionary:(NSDictionary *)JSONDictionary {
self.photos = [JSONDictionary["photos"] transformedArrayUsingBlock:^Photo *(NSDictionary *photoJSON) {
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:self.managedObjectContext];
Photo *photo = [[Photo alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:self.managedObjectContext];
[photo updateWithDictionary:photoJSON];
return photo;
}];
}
This update
method could theoretically be called on the same Tweet
object multiple times, as the user refreshes their timeline. The code above would result in Photo
objects being orphaned as new ones are created to take their place.
I can think of three decent ways to avoid this:
This would entail:
- Creating identifiers for each photo
- Updating photos that already exist
- Creating photos that don't already exist
- Deleting photos that exist on disk but not in the JSON response
Seems like more work than it's worth to be honest
- (void)updateWithDictionary:(NSDictionary *)JSONDictionary {
[self.photos enumerateObjectsUsingBlock:^(Photo *photo, NSUInteger photoIndex, BOOL *stop) {
[self.managedObjectContext deleteObject:photo];
}];
self.photos = [JSONDictionary["photos"] transformedArrayUsingBlock:^Photo *(NSDictionary *photoJSON) {
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Photo" inManagedObjectContext:self.managedObjectContext];
Photo *photo = [[Photo alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:self.managedObjectContext];
[photo updateWithDictionary:photoJSON];
return photo;
}];
}
Would result in some unnecessary deleting and re-creating of the same data, but would be far simpler than #1.
@implementation Photo
- (void)willSave {
if (!self.tweet) {
[self.managedObjectContext deleteObject:self];
}
}
This is slightly cleaner than manually deleting the photos (in my opinion), but doesn't scale particularly well. It requires me to create the tweet
inverse relationship (with approaches 1-2, the Photo
doesn't actually need to have a reference to the Tweet
).
Additionally, Photo
could be generic and used in contexts other than tweets. Maybe a Photo
can also be associated with a DM, or a user's avatar, in which case I'd need to create inverse relationships for all three and the willSave
implementation will now look like:
@implementation Photo
- (void)willSave {
if (!self.tweet && !self.user && !self.directMessage) {
[self.managedObjectContext deleteObject:self];
}
}
I’m still a fan of 3.