2016-04-18 2 views
0

Je rencontre des difficultés lorsque j'ai un élément dans mon UITableView et je mets à jour la valeur d'attribut qui détermine la section.Les lignes dans les sections ne sont pas mises à jour dans TableView

J'ai compris qu'il avait quelque chose à voir avec didChangeSection et l'option NSFetchedResultsChangeType.Update. Mais c'est aussi loin que je suis capable d'obtenir.

Je ne suis pas sûr du code que je dois mettre là-bas qui mettrait à jour le nombre de lignes dans une section.

Ceci est le code d'erreur exact que je reçois:

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)

Et voici le code dans mon contrôleur de vue:

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 
    } 

} 

} 

Je sens que je suis vraiment proche de l'obtenir à droite, mais j'ai juste besoin de cette poussée supplémentaire.

Répondre

0

Il s'avère que ce n'était pas un problème avec didChangeSection et NSFetchedResultsChangeType.Update. C'était un problème avec didChangeObject et NSFetchedResultsChangeType.Move.

Le code suivant a corrigé le problème. Tout le reste est le même, donc je vais juste mettre ces deux fonctions.

Ajouté NSFetchedResultsChangeType.Move et à l'intérieur je supprime l'ancien emplacement et le nouvel emplacement.

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 
    } 

} 

Suppression NSFetchedResultsChangeType.Update depuis le déménagement se charge de la mise à jour de la section.

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

} 

Espoirs cette aide quelqu'un d'autre!

1

Essayez de recharger les lignes dans la mise à jour vous parlez et de vérifier cela si elle aide https://forums.developer.apple.com/thread/12184

+0

Donc, vous pensez que ce n'est pas un problème avec mon code, mais plutôt un problème avec Xcode? –

+0

Peut-être Oui, c'est ce que le thread a dit, essayez de vérifier avec les points d'arrêt combien de fois la méthode déléguée se déclenche et lors de la mise à jour, insertion ou suppression de NSFetchedResultsChangeType exécute .First essayez de recharger les lignes. –