如何调用didChangeSection强制更新swift中的节

时间:2016-05-24 02:31:10

标签: uitableview core-data swift2 nsfetchedresultscontroller

我一直遇到来自相关实体的CoreData和Sections的问题。为了显示我的问题,我制作了尽可能简单的应用版本。如果您想下载它,这是该文件的链接。 https://www.dropbox.com/s/y7gcpu7qq2mnrye/Sample%20List%20App.zip?dl=0

它只是一个tableview,点击加号按钮会添加一个新项目,其中数量为1,名称为1,部分为1.然后单击单元格将它们全部递增。您可以看到名称和数量都正在更新,但该部分永远不会更新。这似乎是因为frc没有跟踪Section Table中的更改,但是对目录或项表没有问题。当我退出应用程序然后再次启动它时,这些部分正确加载。这是我当前的实体和关系(简单应用程序)

enter image description here

以下是tableviewcontroller的代码。

import UIKit
import CoreData

class TableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

// MARK: - Constants and Variables

let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
var frc: NSFetchedResultsController = NSFetchedResultsController()

// MARK: - App loading Functions

override func viewDidLoad() {
    super.viewDidLoad()

    frc = getFCR()
    frc.delegate = self

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

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

// MARK: - Outlets and Actions

@IBAction func addItemPress(sender: UIBarButtonItem) {

    var entityDesc = NSEntityDescription.entityForName("Items", inManagedObjectContext: self.moc)
    let item = Items(entity: entityDesc!, insertIntoManagedObjectContext: self.moc)

    item.qty = 1

    entityDesc = NSEntityDescription.entityForName("Catalog", inManagedObjectContext: self.moc)
    let catalog = Catalog(entity: entityDesc!, insertIntoManagedObjectContext: self.moc)

    catalog.name = 1

    var section: Sections?
    if (checkSectionName(0, moc: self.moc) == false) {
        entityDesc = NSEntityDescription.entityForName("Sections", inManagedObjectContext: self.moc)
        section = Sections(entity: entityDesc!, insertIntoManagedObjectContext: self.moc)

        section!.section = 1
    } else {
        section = returnSection(0, moc: self.moc)
    }

    item.catalog = catalog
    item.catalog!.sections = section

    do {
        try moc.save()
    } catch {
        fatalError("New item save failed")
    }
}

// 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, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

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

    cell.nameLbl.text = "Item #\(item.catalog!.name!)"
    cell.qtyLbl.text = "Qty: \(item.qty!.stringValue)"

    return cell
}

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

    if let sections = frc.sections {
        let currentSection = sections[section]
        return "Section \(currentSection.name)"
    }

    return nil
}

func controllerWillChangeContent(controller: NSFetchedResultsController) {

    tableView.beginUpdates()
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {

    tableView.endUpdates()
}

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

    switch type {
    case NSFetchedResultsChangeType.Update:
        self.tableView.reloadSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
    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.Move:
        self.tableView.deleteSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
        self.tableView.insertSections(NSIndexSet(index: sectionIndex), withRowAnimation: UITableViewRowAnimation.Automatic)
    }
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {

    switch type {
    case NSFetchedResultsChangeType.Update:
        self.tableView.reloadRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
    case NSFetchedResultsChangeType.Delete:
        self.tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
    case NSFetchedResultsChangeType.Insert:
        self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Fade)
    case NSFetchedResultsChangeType.Move:
        self.tableView.moveRowAtIndexPath(indexPath!, toIndexPath: newIndexPath!)
    }
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    let item: Items = frc.objectAtIndexPath(indexPath) as! Items
    var qty: Int = Int(item.qty!)
    qty = qty + 1

    item.qty = qty

    var name: Int = Int(item.catalog!.name!)
    name = name + 1

    item.catalog!.name = name

    var sec: Int = Int(item.catalog!.sections!.section!)
    sec = sec + 1

    var section: Sections?
    if (checkSectionName(sec, moc: self.moc) == false) {
        let entityDesc = NSEntityDescription.entityForName("Sections", inManagedObjectContext: self.moc)
        section = Sections(entity: entityDesc!, insertIntoManagedObjectContext: self.moc)

        section!.section = sec
    } else {
        section = returnSection(sec, moc: self.moc)
    }

    item.catalog!.sections = section

    do {
        try moc.save()
    } catch {
        fatalError("Edit item save failed")
    }

}

func fetchRequest() -> NSFetchRequest {

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

    return fetchRequest

}

func getFCR() -> NSFetchedResultsController {

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

    return frc

}

func checkSectionName(sectionName: NSNumber, moc: NSManagedObjectContext) -> Bool {

    var exists: Bool = false

    let fetchReq = NSFetchRequest(entityName: "Sections")
    let pred = NSPredicate(format: "section == %@", sectionName)
    fetchReq.predicate = pred

    do {
        let check = try moc.executeFetchRequest(fetchReq)
        for rec in check {
            if let name = rec.valueForKey("section") {
                if (name as! NSNumber == sectionName) {
                    exists = true
                }
            }
        }
    } catch {
        fatalError("Failed fetching records when checking if List name already exists")
    }

    return exists

}

func returnSection(sectionName: NSNumber, moc: NSManagedObjectContext) -> Sections {

    let fetchReq = NSFetchRequest(entityName: "Sections")
    let pred = NSPredicate(format: "section == %@", sectionName)
    fetchReq.predicate = pred

    do {
        let check = try moc.executeFetchRequest(fetchReq)
        return check.first! as! Sections
    } catch {
        fatalError("Failed fetching records to return section")
    }
}

}

1 个答案:

答案 0 :(得分:1)

稍微玩一下之后,如果didChangeSection中指定的第一个关系被直接修改(例如,在这种情况下,如果你创建一个新的{{}},那么sectionNameKeyPath似乎只会被触发。 1}}链接到正确的部分,并设置Catalog)。但我认为这太复杂,无法解决。

一种解决方案是更改FRC以获取item.catalog = newCatalog个对象而不是Catalog。由于它们映射一对一,因此表视图应保留相同的结构。关键变化是:

Items

func fetchRequest() -> NSFetchRequest {

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

    return fetchRequest
}

然后修改对func getFCR() -> NSFetchedResultsController { frc = NSFetchedResultsController(fetchRequest: fetchRequest(), managedObjectContext: moc, sectionNameKeyPath: "sections.section" , cacheName: nil) return frc } 的引用以反映此更改:

frc

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

    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! TableViewCell
    let catalog: Catalog = frc.objectAtIndexPath(indexPath) as! Catalog

    cell.nameLbl.text = "Item #\(catalog.name!)"
    cell.qtyLbl.text = "Qty: \(catalog.items.qty!.stringValue)"

    return cell
}

因为您要直接修改override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let catalog: Catalog = frc.objectAtIndexPath(indexPath) as! Catalog var qty: Int = Int(catalog.items.qty!) qty = qty + 1 catalog.items.qty = qty var name: Int = Int(catalog.name!) name = name + 1 catalog.name = name var sec: Int = Int(catalog.sections.section!) sec = sec + 1 var section: Sections? if (checkSectionName(sec, moc: self.moc) == false) { let entityDesc = NSEntityDescription.entityForName("Sections", inManagedObjectContext: self.moc) section = Sections(entity: entityDesc!, insertIntoManagedObjectContext: self.moc) section!.section = sec } else { section = returnSection(sec, moc: self.moc) } catalog.sections = section do { try moc.save() } catch { fatalError("Edit item save failed") } } 对象的sections属性,所以会触发catalog方法。