I've been building up my app slowly. Previously, I had two entities in CoreData. One called Items and the other called Catalog. The goal was to have my app remember items that were added so the user wouldn't have to add in all the attributes again, and Catalog would store all the attributes of the item but Items would be the current active instance of the item.
Below is my code I had working where both Catalog and Items were duplicating information, and if I updated a record, both didChangeObject and didChangeSection were called correctly and my tableview would update correctly.
func editItem() {
item!.name = trimSpaces(itemName.text!)
item!.brand = trimSpaces(itemBrand.text!)
item!.qty = Float(itemQty.text!)
item!.price = currencyToFloat(itemPrice.text!)
item!.size = trimSpaces(itemSize.text!)
item!.section = trimSpaces(itemSection.text!)
item!.image = UIImageJPEGRepresentation(itemImage.image!, 1)
catalog!.name = trimSpaces(itemName.text!)
catalog!.brand = trimSpaces(itemBrand.text!)
catalog!.qty = Float(itemQty.text!)
catalog!.price = currencyToFloat(itemPrice.text!)
catalog!.size = trimSpaces(itemSize.text!)
catalog!.section = trimSpaces(itemSection.text!)
catalog!.image = UIImageJPEGRepresentation(itemImage.image!, 1)
do {
try moc.save()
} catch {
fatalError("Edit Item save failed")
}
if (itemProtocal != nil) {
itemProtocal!.finishedEdittingItem(self, item: self.item!)
}
}
But when I remove all the duplicate attributes between Catalog and Items and add a one to one relationship. Now only didChangeObject gets called but not didChangeSection. * Updated with pbasdf suggestions *
func editItem() {
let item: Items = self.item!
item.qty = Float(itemQty.text!)
item.catalog!.name = trimSpaces(itemName.text!)
item.catalog!.brand = trimSpaces(itemBrand.text!)
item.catalog!.qty = Float(itemQty.text!)
item.catalog!.price = currencyToFloat(itemPrice.text!)
item.catalog!.size = trimSpaces(itemSize.text!)
item.catalog!.section = trimSpaces(itemSection.text!)
item.catalog!.image = UIImageJPEGRepresentation(itemImage.image!, 1)
do {
try moc.save()
} catch {
fatalError("Edit Item save failed")
}
if (itemProtocal != nil) {
itemProtocal!.finishedEdittingItem(self, item: self.item!)
}
}
**Note: in the first code I'm accessing the item and catalog variables that are set at the Class level. But in the new version, I wanted it to be unwrapped, so I am defining the item inside the function instead. The catalog is now coming from the relationship though.
Below are my didChangeObject and didChangeSection code, which doesn't change between the new and old version.
func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) {
switch type {
case NSFetchedResultsChangeType.Update:
self.tableView.reloadSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Delete:
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Insert:
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Move:
self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
switch type {
case NSFetchedResultsChangeType.Delete:
self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Insert:
self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Fade)
case NSFetchedResultsChangeType.Update:
self.tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Move:
self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
I'm still pretty new at programming in iOS, but my guess of what is happening is that the tableview is being populated by the Items Entity. Before, the tableview Section was being populated by item.section (which was inside Items) but now tableview Section is coming from the relationship with Catalog (items.catalog > catalog.section) if that makes any sense. So then when I update the managedObectContect, it isn't registering that the Section is being updated.
One thing to note though, when I close the app and open it again, it'll fix the Section. So it is loading correctly, and inserting correctly, just not updating correctly. I'm assuming that there is some other call I need to do to let the section know it is being changed, but I don't have a clue of what it would be, and google didn't know the answer, or more likely, with how I was asking it didn't know the answer.
Thank you for any help and let me know if you need me to include screenshots or additional code to explain better what is happening.
Adding in FRC and fetchRequest code
func fetchRequest() -> NSFetchRequest {
let fetchRequest = NSFetchRequest(entityName: "Items")
let sortDesc1 = NSSortDescriptor(key: "catalog.section", ascending: true)
let sortDesc2 = NSSortDescriptor(key: "isChecked", ascending: true)
let sortDesc3 = NSSortDescriptor(key: "catalog.name", ascending: true)
fetchRequest.sortDescriptors = [sortDesc1, sortDesc2, sortDesc3]
return fetchRequest
}
func getFCR() -> NSFetchedResultsController {
frc = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "catalog.section" , cacheName: nil)
return frc
}
Adding in Create New Item Code
func createNewItem() {
//Items Class Save
var entityDesc = NSEntityDescription.entityForName("Items", inManagedObjectContext: moc)
let item = Items(entity: entityDesc!, insertIntoManagedObjectContext: moc)
let id = NSUserDefaults.standardUserDefaults().integerForKey("nextItemID")
if (itemQty.text! == "") {
item.qty = 1
} else {
item.qty = Float(itemQty.text!)
}
item.isChecked = false
//Catalog Clase Save
entityDesc = NSEntityDescription.entityForName("Catalog", inManagedObjectContext: moc)
let catalog = Catalog(entity: entityDesc!, insertIntoManagedObjectContext: moc)
catalog.id = id
catalog.name = trimSpaces(itemName.text!)
catalog.brand = trimSpaces(itemBrand.text!)
if (itemQty.text == "") {
catalog.qty = 1
} else {
catalog.qty = Float(itemQty.text!)
}
catalog.price = currencyToFloat(itemPrice.text!)
catalog.size = trimSpaces(itemSize.text!)
catalog.section = trimSpaces(itemSection.text!)
catalog.image = UIImageJPEGRepresentation(itemImage.image!, 1)
item.catalog = catalog
do {
try moc.save()
NSUserDefaults.standardUserDefaults().setObject(id + 1, forKey: "nextItemID")
NSUserDefaults.standardUserDefaults().synchronize()
} catch {
fatalError("New item save failed")
}
}