I am trying to set a constraint in core data with the new Entity Constraints inspector (To make the name of the item unique). All that I've read says it's pretty simple - Set the constraint and handle the error. I don't get any errors and can add the same entry as many times as I want.
The app does require IOS 9.0, Xcode tools requirement is set to 7.0
The constraint, category1Name, is a String.
My addItem code is:
func addNewRecord() {
//check to be sure the entry is not empty
if (categoryTextField.text == "") {
//prompt requiring a name
let ac = UIAlertController(title: nil, message: "Name Required", preferredStyle: .Alert)
ac.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))
self.presentViewController(ac, animated: true, completion: nil)
} else {
let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName("Category1", inManagedObjectContext: kAppDelegate.managedObjectContext) as! Category1
newManagedObject.category1Name = categoryTextField.text
newManagedObject.category1Description = categoryTextView.text
//bunch more items...
//save it
kAppDelegate.saveContext()
makeEntryFieldsEnabledNO()
performSegueWithIdentifier("unwindToCategoriesTableViewController", sender: self)
}//if else
}//addNewRecord
The AppDelegate save is standard:
func saveContext () {
if managedObjectContext.hasChanges {
do {
try managedObjectContext.save()
} catch {
//insert your standard error alert stuff here
let nserror = error as NSError
print("From the print line: Unresolved error \(nserror), \(nserror.userInfo)")
abort()
}//do catch
}//if moc
}//saveContext
Here's the Core Data constraint:
This app is iCloud enabled.
The managedObjectContext merge policy is set to NSMergeByPropertyObjectTrumpMergePolicy
lazy var managedObjectContext: NSManagedObjectContext = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
managedObjectContext.persistentStoreCoordinator = coordinator
managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
return managedObjectContext
}()//var managedObjectContext
Any guidance would be appreciated.
It would appear Apple have finally fixed the crazy Xcode problem where changes you make in a data model file don't actually change.
Putting that aside, the current formula seems to be:
in your core data singleton ...
container = NSPersistentContainer(name: _nom)
// during development, right HERE likely delete the sql database file
// and start fresh, as described here stackoverflow.com/a/60040554/294884
container.loadPersistentStores { storeDescription, error in
if let error = error {
print("\n ERROR LOADING STORES! \(error) \n")
}
else {
print("\n STORES LOADED! \(storeDescription) \n")
}
self.container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
self.container.viewContext.automaticallyMergesChangesFromParent = true
}
Then in your data model file
Then when you add new data, you must
perform
Easy right?
So something like
let pm = core.container.newBackgroundContext()
pm.perform {
for onePerson in someNewData {
... create your new CDPerson entity ...
}
pm.bake()
}
Note that the bake routine is within the perform block,
and it looks like this:
func bake() {
self.performAndWait {
if self.hasChanges {
do {
try self.save()
}
catch {
print("bake disaster type 1 \(error)")
}
}
// OPTIONALLY, SEE BELOW
if core.container.viewContext.hasChanges {
do {
try core.container.viewContext.save()
}
catch {
print("bake disaster type 2 \(error)")
}
}
// OPTIONALLY, SEE BELOW
}
}
To be clear, notice the pm.bake
... in the function bake()
, the self
in the first half is indeed that newBackgroundContext
which is created for the loop inside the perform.
Nowadays automaticallyMergesChangesFromParent
seems to work perfectly, if you "do everything in the long list above".
• In the bake above, add a couple print lines to see what is saved to the viewContext. You'll see that nothing, at all, is ever saved. It's all done properly by the child/whatever relationships in the engine
• So in fact, in reality you can just omit that passage of the code. All you have to do is
func bake() {
self.performAndWait {
if self.hasChanges {
do {
try self.save()
}
catch {
print("bake disaster type 1 \(error)")
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With