0

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")
    }

}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Jason Brady
  • 1,560
  • 1
  • 17
  • 40
  • 2
    Your analysis is correct - FRCs observe only changes to the objects fetched, not their related objects. See [this answer](http://stackoverflow.com/a/12379824/3985749) - there's no magic call you need to make; just "touch" the item object itself (eg. `catalog.item.qty = catalog.item.qty`) when you update the category. – pbasdf May 15 '16 at 19:06
  • I think I understand what you are say. I tried implementing what you just put in, and I also tried adding item to the front since the FRC is on Items entity not the Catalog. I did something similar to this item.catalog!.name = trimSpaces(itemName.text!) on all the catalog in the second group of code I have above. But this didn't seem to have caused the Sections to update on the tableview either. I then went even further and added what you had in your suggestion catalog.item.qty = catalog.item.qty but that didn't cause the Sections to update either. – Jason Brady May 15 '16 at 19:29
  • I was, however, before making your suggested changes and after seeing all the labels update correctly that were the catalog attributes since the didChangeObject event was being called, just not the Sections since the didChangeSections event wasn't being called. I'll keep playing with it, but if you have any other suggestions I'd much appreciate it. Thank you again! – Jason Brady May 15 '16 at 19:31
  • ***Also added my FRC and fetchRequest Code – Jason Brady May 15 '16 at 19:34
  • I'm afraid I can't see any reason why `didChangeObject` would be called but not `didChangeSection`. Is the `editItem` method the only place where you update either object? – pbasdf May 15 '16 at 20:00
  • I updated the code you suggested changing and also put in my code for the Create New Item, just incase that is help. That one behaves completely fine and calls both the didChangeObject and didChangeSection – Jason Brady May 15 '16 at 20:09
  • Here is a sample Xcode that is essentially the same thing and has the same problem. `didchangeObject` gets called, just never `didChangeSection`. Note, clicking the plus button adds a new record. Clicking the cell increments the name, qty, and Section. But you only see name and qty change. Stoping and restarting shows the change. https://www.dropbox.com/s/y7gcpu7qq2mnrye/Sample%20List%20App.zip?dl=0 – Jason Brady May 23 '16 at 17:12

0 Answers0