iOS 9 brings some exciting new updates to Core Data. One feature in particular that I wanted to try out was unique constraints. If you’re like me and you have a lot of code that has the following find and update/create pattern, unique constraints can help you simplify your codebase.
managedObjectContext.performBlock {
let createRequest = NSFetchRequest(entityName: "Recipe")
createRequest.resultType = ManagedObjectIDResultType
let predicate = NSPredicate(format: "source = %@ AND externalID = %@", source,externalID)
let results = self.managedObjectContext.executeFetchRequest(createRequest)
if (results.count) {
//update it!
} else {
//create it!
}
}
By implementing unique constraints, you can set an attribute (or multiple attributes) to be unique across all instances of any entity. For instance, maybe we want unique email addresses for User entities, or unique IDs for Part entities.
An important note is that entities with non-unique constraints can still exist simultaneously in your managed object context. Core Data will only look for and resolve conflicts for entities with non-unique constraints when you save your managed object context. So, if you make heavy use of fetched results controllers, this won’t be of much help. But if you have some import process that is likely to have duplicates with no UI, unique constraints will work great.
I’ve created a sample project to show how to get unique constraints working in Core Data. You can view the source on GitHub, and follow along here.
The first thing we’ll need to do is set which attributes are going to be unique on our entities. We can do this in our Core Data model. In our example, we have a Person entity, and we want each person to have a unique name. So we can set name as our constraint.

Next, we’ll have to set a merge policy for our managed object context. For our example, we’ll want to use NSMergeByPropertyObjectTrumpMergePolicy, since we want Core Data to look at our in-memory changes and use those. If we were fetching data from an API, this merge policy would work because our in-memory object would have the latest and greatest data we’d want to keep.
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_managedObjectContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
And finally, we can get rid of all of our find and create/update code. In my Person class, I have two class methods - one to insert a new Person in to our context, and one to generate a “random” name out of 5 names total (which is bound to cause some conflicts).
#pragma mark - Public Methods
+ (nonnull instancetype)insertPersonWithRandomNameInContext:(nonnull NSManagedObjectContext *)context {
Person *p = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
p.name = [self randomPersonName];
return p;
}
#pragma mark - Private Methods
+ (nonnull NSString *)randomPersonName {
NSArray *nameArray = @[@"Harry", @"Zayn", @"Niall", @"Liam", @"Louis"];
NSUInteger rnd = arc4random_uniform((uint32_t)nameArray.count);
return [nameArray objectAtIndex:rnd];
}
Finally, all we have to do is add some objects and save our managed object context to see this in action
for (int i = 0; i < 10; i++) {
[Person insertPersonWithRandomNameInContext:self.context];
}
[self.context save:nil];
And there you have it! That’s all you need to get unique constraints working in Core Data. In my demo project, I’ve used a NSFetchedResultsController to show where unique constraints will not work well. If you’re displaying data using a fetched results controller, you’ll still see entities with non-unique properities, since conflict resolution only happens when saving our managed object context, and fetched results controllers work with in-memory objects.

Hi Zacharyorr, I went through your blog, it was helpful and explain how to set unique attributes in an entity. Can you...