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?
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.