How can I guarantee unique entries in a Core Data store in a shared app container used by both the host app and an extension? How can I guarantee unique entries in a Core Data store in a shared app container used by both the host app and an extension? ios ios

How can I guarantee unique entries in a Core Data store in a shared app container used by both the host app and an extension?


Is there a known approach to this rather novel problem introduced by iOS 8 extensions?

Yes, it's the same approach that applies when using iCloud with Core Data: let the duplicates happen, but then go and clean them up. Both situations run the risk of creating duplicate entries, and there's no completely reliable way to prevent them. Since you have a uniqueID key, you're in good shape as far as this is concerned.

It would be a lot easier, as Dave DeLong notes, to avoid the problem in the first place. If that's impossible, you can deal with it, with some extra work.

Finding duplicates would be something like:

NSError *error = nil;NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];[moc setPersistentStoreCoordinator:self.persistentStoreCoordinator];NSFetchRequest *fr = [[NSFetchRequest alloc] initWithEntityName:@"MyEntityName"];[fr setIncludesPendingChanges:NO];NSExpression *countExpr = [NSExpression expressionWithFormat:@"count:(uniqueID)"];NSExpressionDescription *countExprDesc = [[NSExpressionDescription alloc] init];[countExprDesc setName:@"count"];[countExprDesc setExpression:countExpr];[countExprDesc setExpressionResultType:NSInteger64AttributeType];NSAttributeDescription *uniqueIDAttr = [[[[[_psc managedObjectModel] entitiesByName] objectForKey:@"MyEntityName"] propertiesByName] objectForKey:@"uniqueID"];[fr setPropertiesToFetch:[NSArray arrayWithObjects:uniqueIDAttr, countExprDesc, nil]];[fr setPropertiesToGroupBy:[NSArray arrayWithObject:uniqueIDAttr]];[fr setResultType:NSDictionaryResultType];NSArray *countDictionaries = [moc executeFetchRequest:fr error:&error];

This is pretty much the Core Data equivalent of something like this in SQL:

SELECT uniqueID, COUNT(uniqueID) FROM MyEntityName GROUP BY uniqueID;

You get an array of dictionaries, each of which contains a uniqueID and a count of the number of times that value is used. Run through the dictionary and deal with duplicates appropriately.

I described this in more detail in a blog post. There's also a sample project from Apple that demonstrates the process, called SharedCoreData, but I believe it's only available as part of the WWDC 2012 sample code bundle. It was also described in session 227 at that conference.


It seems like the simplest approach to this would be to simply avoid the multiple writers in the first place. Why not just drive your extensions entirely off cached data, and then only update your data store from your primary iOS app?