TableView

时间:2016-04-18 03:17:40

标签: uitableview core-data xcode6 swift2

我在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
    }

}

}

我觉得我真的很接近正确,但我只需要额外的推动。

2 个答案:

答案 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
    }

}

希望这有助于其他人!