Understanding Core Data Merge Policies

Miroslav Perović
3 min readMay 15, 2023

--

In the previous article we wrote how to handle the constraint errors. Today we will learn more about merge policies.

When multiple contexts are working on the same persistent store, conflicts can arise if they try to modify the same object. The merge policy determines how these conflicts are resolved. Core Data provides several built-in merge policies, including:

  • NSMergeByPropertyObjectTrumpMergePolicy: This merge policy takes the values from the changes made in the context and overwrites any conflicting values in the persistent store.
  • NSMergeByPropertyStoreTrumpMergePolicy: This merge policy takes the values from the persistent store and overwrites any conflicting values in the context.
  • NSOverwriteMergePolicy: This merge policy overwrites the persistent store with the values from the context, regardless of any conflicts.
  • NSRollbackMergePolicy: This merge policy rolls back any changes made in the context and uses the values from the persistent store.
  • NSErrorMergePolicy: Default merge policy for all managed object context. If a save fails because of conflicting objects, you can find IDs of those objects in error’s userInfo dictionary (look at my previous article to find more about parsing userInfo)

These merge policies can be set on the NSManagedObjectContext, which is responsible for managing a collection of managed objects.

Overwrite for Constraint Violations

You can set a merge policy so that when you run into a constraint violation, the new data object overwrites the old one. Here’s an example:

struct AddNewUserView: View {
@Environment(\.managedObjectContext) private var moc

@State private var firstName = ""
@State private var lastName = ""
@State private var email = ""
var body: some View {
VStack {
TextField("Enter First Name", text: $firstName)
.textFieldStyle(.roundedBorder)
.padding()
TextField("Enter Last Name", text: $lastName)
.textFieldStyle(.roundedBorder)
.padding()
TextField("Enter Email", text: $email)
.keyboardType(.emailAddress)
.textInputAutocapitalization(.never)
.textFieldStyle(.roundedBorder)
.padding()
Button("Add") {
let newUser = User(context: moc)
newUser.firstName = firstName
newUser.lastName = lastName
newUser.email = email

try! moc.save()

firstName = ""
lastName = ""
email = ""
}
}
.onAppear {
moc.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
}
}
}

Note: I’m setting the merge policy into onAppear block for demonstration purposes. Usually developers set it after creating the NSPersistentContainer. Also, we can use try! moc.save() because the merge policy will handle the constraint violation.

Keep during Constraint Violations

You can set a merge policy so that when you run into a constraint violation, the new data object overwrites the old one. Here’s an example:

We can replace code in onAppear with:

moc.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump

Note: This merge policy name looks a lot like the previous one except it is using ‘store’ instead of ‘Object’. In Core Data ‘Store’ means the persistent store where the original data object is and that’s the one that will survive after a merge conflict.

Note 2: ‘Trump’ is another way saying ‘override’

Manualy Merge Conflicts

In some cases, it may be necessary to handle merge conflicts manually. Core Data provides a way to detect merge conflicts by listening for the NSManagedObjectContextDidSave notification. This notification is sent when changes are saved to the persistent store. You can then compare the changes made in the context with the changes in the persistent store and resolve any conflicts manually.

Conclusion

Core Data’s merge policy is an important feature that determines how conflicts are resolved when multiple contexts are working on the same persistent store. Swift provides an easy way to set the merge policy on a NSManagedObjectContext instance. By understanding the different merge policies and how they work, you can ensure that your Core Data implementation is handling conflicts correctly and efficiently.

--

--