2016-04-18 8 views
0

Ich habe eine harte Zeit, wenn ich ein Element in meinem UITableView habe und ich den Attributwert aktualisieren, der den Abschnitt bestimmt.Zeilen in Abschnitten zählen nicht aktualisiert in TableView

Ich habe herausgefunden, dass es etwas mit didChangeSection und der Option NSFetchedResultsChangeType.Update zu tun hat. Aber soweit kann ich das bekommen.

Ich bin mir nicht sicher, welchen Code ich dort eingeben muss, um die Anzahl der Zeilen in einem Abschnitt zu aktualisieren.

Dies ist der genaue Fehlercode Ich erhalte:

2016-04-17 20:00:37.126 EZ List[13722:1469523] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit_Sim/UIKit-3512.60.7/UITableView.m:1716 2016-04-17 20:00:37.126 EZ List[13722:1469523] CoreData: error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (3), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). with userInfo (null)

Und das ist der Code in meinem View-Controller:

import UIKit 
import CoreData 

class ListItemsTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { 

let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext 
var frc: NSFetchedResultsController = NSFetchedResultsController() 
var list: Lists? 
var catalog: Catalog? 

override func viewDidLoad() { 
    super.viewDidLoad() 

    self.tableView.reloadData() 
    self.title = list?.name 

    frc = getFCR() 
    frc.delegate = self 

    do { 
     try frc.performFetch() 
    } catch { 
     print("Failed to perform inital fetch") 
    } 

    // Uncomment the following line to preserve selection between presentations 
    //self.clearsSelectionOnViewWillAppear = true 

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller. 
    // self.navigationItem.rightBarButtonItem = self.editButtonItem() 
} 

override func viewWillAppear(animated: Bool) { 

    let imageView = UIImageView(image: UIImage(named: "TableBackground")) 
    imageView.contentMode = .ScaleAspectFill 
    self.tableView.backgroundView = imageView 
    self.tableView.tableFooterView = UIView(frame: CGRectZero) 

} 

override func viewDidAppear(animated: Bool) { 

    frc = getFCR() 
    frc.delegate = self 

    do { 
     try frc.performFetch() 
    } catch { 
     fatalError("Failed to perform inital fetch") 
    } 

    self.tableView.reloadData() 

} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 

// MARK: - Table view data source 

override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 

    if let sections = frc.sections { 
     return sections.count 
    } 

    return 0 

} 

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

    if let sections = frc.sections { 
     let currentSection = sections[section] 
     return currentSection.numberOfObjects 
    } 

    return 0 

} 

override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 

    if let sections = frc.sections { 
     let currentSection = sections[section] 
     return currentSection.name 
    } 

    return nil 

} 

override func tableView(tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { 

    let header: UITableViewHeaderFooterView = view as! UITableViewHeaderFooterView 
    header.contentView.backgroundColor = UIColor(red: 84/255, green: 200/255, blue: 214/255, alpha: 0.5) 
    header.textLabel!.textColor = UIColor.whiteColor() 
    //header.alpha = 0.5 //make the header transparent 

} 

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

    let cell = tableView.dequeueReusableCellWithIdentifier("listContentCell", forIndexPath: indexPath) as! ListItemsTableViewCell 
    let item = frc.objectAtIndexPath(indexPath) as! Items 

    cell.separatorInset = UIEdgeInsets(top: 0, left: 78, bottom: 0, right: 0) 
    cell.itemName.text = item.name 
    cell.itemSection.text = item.section 
    cell.itemQty.text = "Qty: \(item.qty!)" 
    cell.itemSize.text = item.size 
    cell.itemPrice.text = floatToCurrency(Float(item.cost!)) 
    cell.itemImage.image = UIImage(data: item.image!) 
    cell.itemID.text = String(item.id!) 

    return cell 

} 

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { 

    cell.backgroundColor = UIColor.clearColor() 

} 

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? { 

    let delete = UITableViewRowAction(style: .Destructive, title: "Delete") { (action, indexPath) in 

     let request = self.fetchRequest() 
     var fetchResults = [AnyObject]() 

     do { 
      fetchResults = try self.moc.executeFetchRequest(request) 
     } catch { 
      fatalError("Fetching Data to Delete Failed") 
     } 

     self.moc.deleteObject(fetchResults[indexPath.row] as! NSManagedObject) 
     fetchResults.removeAtIndex(indexPath.row) 

     do { 
      try self.moc.save() 
     } catch { 
      fatalError("Failed to Save after Delete") 
     } 

    } 

    let edit = UITableViewRowAction(style: .Normal, title: "Edit") { (action, indexPath) in 

     // Code to come 

    } 

    let qty = UITableViewRowAction(style: .Normal, title: "Qty") { (action, indexPath) in 

     // Code to come 

    } 

    edit.backgroundColor = UIColor.init(red: 84/255, green: 200/255, blue: 214/255, alpha: 1) 

    return [delete, edit, qty] 

} 

func controllerWillChangeContent(controller: NSFetchedResultsController) { 

    tableView.beginUpdates() 

} 

func controllerDidChangeContent(controller: NSFetchedResultsController) { 

    tableView.endUpdates() 

} 

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.Automatic) 
    case NSFetchedResultsChangeType.Update: 
     let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! ListItemsTableViewCell 
     let item = self.frc.objectAtIndexPath(indexPath!) as! Items 

     cell.itemName.text = item.name 
     cell.itemSection.text = item.section 
     cell.itemQty.text = "Qty: \(item.qty!)" 
     cell.itemSize.text = item.size 
     cell.itemPrice.text = floatToCurrency(Float(item.cost!)) 
     cell.itemImage.image = UIImage(data: item.image!) 
     cell.itemID.text = String(item.id!) 
    default: 
     print("didChangeObject Default was accessed") 
     break 
    } 

} 

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { 

    switch type { 
    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.Update: 
     self.tableView.reloadData() 
    default: 
     print("didChangeSection Default was accessed") 
     break 
    } 

} 

func fetchRequest() -> NSFetchRequest { 

    let fetchRequest = NSFetchRequest(entityName: "Items") 
    let sortDesc1 = NSSortDescriptor(key: "section", ascending: true) 
    let sortDesc2 = NSSortDescriptor(key: "isChecked", ascending: true) 
    let sortDesc3 = NSSortDescriptor(key: "name", ascending: true) 
    fetchRequest.sortDescriptors = [sortDesc1, sortDesc2, sortDesc3] 

    return fetchRequest 

} 

func getFCR() -> NSFetchedResultsController { 

    frc = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "section" , cacheName: nil) 

    return frc 

} 

func getCatalog(id: NSNumber) -> Catalog { 

    var cat: Catalog? 

    let fetchReq = NSFetchRequest(entityName: "Catalog") 
    let pred = NSPredicate(format: "%K == %@", "id", id) 
    fetchReq.predicate = pred 

    do { 
     let check = try moc.executeFetchRequest(fetchReq) 
     cat = (check.first as! Catalog) 
    } catch { 
     fatalError("Failed fetching Catalog Entry matching Item") 
    } 

    return cat! 
} 

func floatToCurrency(flt: Float) -> String { 

    let formatter = NSNumberFormatter() 
    formatter.numberStyle = NSNumberFormatterStyle.CurrencyStyle 
    return String(formatter.stringFromNumber(flt)!) 

} 

/* 
// Override to support conditional editing of the table view. 
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { 
    // Return false if you do not want the specified item to be editable. 
    return true 
} 
*/ 

/* 
// Override to support editing the table view. 
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { 
    if editingStyle == .Delete { 
     // Delete the row from the data source 
     tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) 
    } else if editingStyle == .Insert { 
     // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 
    }  
} 
*/ 

/* 
// Override to support rearranging the table view. 
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { 

} 
*/ 

/* 
// Override to support conditional rearranging of the table view. 
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool { 
    // Return false if you do not want the item to be re-orderable. 
    return true 
} 
*/ 

// MARK: - Navigation 

// In a storyboard-based application, you will often want to do a little preparation before navigation 
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 

    var id: NSNumber 

    if (segue.identifier == "listItemView") { 
     let cell = sender as! UITableViewCell 
     let indexPath = self.tableView.indexPathForCell(cell) 

     let itemCont: ViewItemViewController = segue.destinationViewController as! ViewItemViewController 
     let item: Items = self.frc.objectAtIndexPath(indexPath!) as! Items 
     itemCont.item = item 
     id = item.id! 
     itemCont.catalog = getCatalog(id) 
    } else if (segue.identifier == "listItemViewEdit") { 
     let cell = sender as! UITableViewCell 
     let indexPath = self.tableView.indexPathForCell(cell) 

     let itemCont: AddItemListViewController = segue.destinationViewController as! AddItemListViewController 
     let item: Items = self.frc.objectAtIndexPath(indexPath!) as! Items 
     itemCont.item = item 
     id = item.id! 
     itemCont.catalog = getCatalog(id) 
     itemCont.list = list 
    } 

} 

} 

ich, wie ich es mir wirklich nahe fühlen zu bekommen richtig, aber ich brauche nur diesen zusätzlichen Schub.

Antwort

0

So stellt sich heraus, dass es kein Problem mit didChangeSection und NSFetchedResultsChangeType.Update war. Es war ein Problem mit didChangeObject und NSFetchedResultsChangeType.Move.

Der folgende Code behebt mein Problem. Alles andere ist gleich, also werde ich einfach diese zwei Funktionen setzen.

NSFetchedResultsChangeType.Move hinzugefügt und darin lösche ich den alten Speicherort und den neuen Speicherort.

func controller(controller: NSFetchedResultsController, didChangeSection sectionInfo: NSFetchedResultsSectionInfo, atIndex sectionIndex: Int, forChangeType type: NSFetchedResultsChangeType) { 

    switch type { 
    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.Update: 
     tableView.reloadSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)*/ 
    default: 
     print("didChangeSection Default was accessed") 
     break 
    } 

} 

entfernt NSFetchedResultsChangeType.Update seit dem Umzug kümmert sich um den Abschnitt Aktualisierung.

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.Automatic) 
    case NSFetchedResultsChangeType.Update: 
     let cell = self.tableView.cellForRowAtIndexPath(indexPath!) as! ListItemsTableViewCell 
     let item = self.frc.objectAtIndexPath(indexPath!) as! Items 

     cell.itemName.text = item.name 
     cell.itemSection.text = item.section 
     cell.itemQty.text = "Qty: \(item.qty!)" 
     cell.itemSize.text = item.size 
     cell.itemPrice.text = floatToCurrency(Float(item.cost!)) 
     cell.itemImage.image = UIImage(data: item.image!) 
     cell.itemID.text = String(item.id!) 
    case NSFetchedResultsChangeType.Move: 
     self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic) 
     self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic) 
    } 

} 

Hofft, dass dies jemand anderen hilft!

1

Versuchen Sie, die Zeilen in der Update-Neuladen Sie sprechen und prüfen Sie dies, wenn es hilft https://forums.developer.apple.com/thread/12184

+0

Sie denken also, dass es kein Problem mit meinem Code, sondern ein Problem mit Xcode ist? –

+0

Vielleicht Ja, das ist, was der Thread gesagt hat, versuchen Sie mit Haltepunkten zu überprüfen, wie oft die Delegate-Methode ausgelöst wird und beim Aktualisieren, Einfügen oder Löschen welche der NSFetchedResultsChangeType ausgeführt wird. Versuchen Sie zuerst, die Zeilen neu zu laden. –