Search code examples
swiftcore-datansfetchedresultscontroller

NSBatchUpdateRequest: .Update not firing in didChangeObject


I am building a blog reader while learning Swift. In this I am saving the data to Core Data and having the option to mark the articles as "read". When I mark them individually as read using editActionsForRowsAtIndexPath the tableview.reloadData() works and the cell formatting changes.

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
    let object = fetchedResultsController.objectAtIndexPath(indexPath)
    let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let context:NSManagedObjectContext = appDel.managedObjectContext
    var edit = UITableViewRowAction()
    if let read = object.valueForKey("read") as? Bool{
        if read == true{
            edit = UITableViewRowAction(style: .Normal, title: "Mark\nUnread") { action, index in
                object.setValue(false, forKey: "read")
                do{
                    try context.save()
                }catch{

                }
                tableView.reloadData()
                self.updateReadAll()
            }
            edit.backgroundColor = UIColor(hexaString: "#A1A19E")
        }else{
            edit = UITableViewRowAction(style: .Normal, title: "Mark\nRead") { action, index in
                object.setValue(true, forKey: "read")
                do{
                    try context.save()
                }catch{

                }
                tableView.reloadData()
                self.updateReadAll()
            }
            edit.backgroundColor = UIColor(hexaString: "#A1A19E")
        }
        return [edit]
    }else{
        return []
    }
}

However, when I use NSBatchUpdateRequest the Core Data updates but the cell formatting does not update. I have to force quit the app and relaunch for the cells to appear correctly. I added print("Updated") in didChangeObject to verify it wasn't the configureCell causing the issue.

@IBAction func markReadAction(sender: AnyObject) {
    let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let context:NSManagedObjectContext = appDel.managedObjectContext
    let table = NSBatchUpdateRequest(entityName: "BlogItems")
    table.propertiesToUpdate = ["read":true]
    do{
        try context.executeRequest(table)
    }catch{

    }
    updateReadAll()
    tableView.reloadData()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
        switch type {
            case .Update:
                self.configureCell(tableView.cellForRowAtIndexPath(indexPath!)!, atIndexPath: indexPath!)
                print("Updated")
            case .Insert:
                tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
            case .Delete:
                tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
            case .Move:
                tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
                tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
        }
}

func configureCell(cell: UITableViewCell, atIndexPath indexPath: NSIndexPath) {
    let object = self.fetchedResultsController.objectAtIndexPath(indexPath)
    cell.textLabel!.text = object.valueForKey("title")!.description
    cell.detailTextLabel!.text = object.valueForKey("snippet")!.description
    view.backgroundColor = UIColor(hexaString: "#F8F7F5")
    cell.textLabel!.textColor = UIColor.blackColor()
    cell.detailTextLabel!.textColor = UIColor.blackColor()
    if let read = object.valueForKey("read") as? Bool{
        if read == true{
            cell.textLabel!.textColor = UIColor(hexaString: "#A1A19E")
            cell.detailTextLabel!.textColor = UIColor(hexaString: "#A1A19E")
        }
    }
}

func updateReadAll(){
    if searchCoreData(NSPredicate(format: "read = %@", false)) > 0{
        markReadView.enabled = true
        markReadView.tintColor = UIColor.blackColor()
    }else{
        markReadView.enabled = false
        markReadView.tintColor = UIColor(hexaString: "#A1A19E")
    }
}

Does the didChangeObject not work with batch updates? Is there something else I can do to update the cells?


Solution

  • Watch the video from 2014 WWDC about Batch Updates. Basically the updates are made on disk but your in memory copy of the data is NOT updated. You must update the objects in memory yourself, either resetting the context or refreshing each object individually.