我一直遇到来自相关实体的CoreData和Sections的问题。为了显示我的问题,我制作了尽可能简单的应用版本。如果您想下载它,这是该文件的链接。 https://www.dropbox.com/s/y7gcpu7qq2mnrye/Sample%20List%20App.zip?dl=0
它只是一个tableview,点击加号按钮会添加一个新项目,其中数量为1,名称为1,部分为1.然后单击单元格将它们全部递增。您可以看到名称和数量都正在更新,但该部分永远不会更新。这似乎是因为frc没有跟踪Section Table中的更改,但是对目录或项表没有问题。当我退出应用程序然后再次启动它时,这些部分正确加载。这是我当前的实体和关系(简单应用程序)
以下是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")
}
}
}
答案 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
方法。