我在UITableView中有一个项目时遇到困难,我更新了确定Section的属性值。
我发现它与didChangeSection和NSFetchedResultsChangeType.Update选项有关。但就我而言,这就是我能得到的。
我不确定我需要在那里添加哪些代码来更新部分中的行数。
这是我得到的确切错误代码:
2016-04-17 20:00:37.126 EZ列表[13722:1469523] ***断言失败 - [UITableView _endCellAnimationsWithContext:],/ BuildRoot / Library / Cache / com.apple.xbs / Source / UIKit_Sim / UIKit的-3512.60.7 / UITableView.m:1716 2016-04-17 20:00:37.126 EZ列表[13722:1469523] CoreData:错误:严重的应用程序错误。在调用-controllerDidChangeContent:期间,从NSFetchedResultsController的委托中捕获到异常。无效更新:第0节中的行数无效。更新(2)后现有部分中包含的行数必须等于更新前该部分中包含的行数(3),加上或减去数字从该部分插入或删除的行(0插入,0删除)和加或减移入或移出该部分的行数(0移入,0移出)。 with userInfo(null)
这是我的视图控制器中的代码:
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
}
}
}
我觉得我真的很接近正确,但我只需要额外的推动。
答案 0 :(得分:1)
尝试重新加载您正在讨论的更新中的行,并检查它是否有帮助 https://forums.developer.apple.com/thread/12184
答案 1 :(得分:0)
事实证明,这与didChangeSection和NSFetchedResultsChangeType.Update不同。这是didChangeObject和NSFetchedResultsChangeType.Move的一个问题。
以下代码修复了我的问题。其他一切都是一样的,所以我将把这两个功能放在一起。
添加了NSFetchedResultsChangeType.Move并在其中删除旧位置和新位置。
<g>
删除了NSFetchedResultsChangeType.Update,因为移动会处理Section更新。
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
}
}
希望这有助于其他人!