未从相关实体快速调用节更新事件 [英] Section update event not being called from related entity in swift

查看:280
本文介绍了未从相关实体快速调用节更新事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是一个链接,用于下载我的应用程序的简化版本,该问题完全相同。顶部的加号添加按钮添加一个新记录,该新记录设置为name = 1,qty = 1和section =1。选择一个单元格会将它们全部递增到下一个数字。您可以看到名称和数量都已更新,但是该部分直到您退出应用程序并重新启动后才更新。



在我的TableViewController中,使用以下代码创建我的FetchRequestController(frc):

  func fetchRequest()-> NSFetchRequest {

let fetchRequest = NSFetchRequest(entityName: Items)
let sortDesc1 = NSSortDescriptor(key: catalog.sections.section,升序:true)
let sortDesc2 = NSSortDescriptor(键: isChecked,升序:true)
let sortDesc3 = NSSortDescriptor(键: catalog.name,升序:true)
fetchRequest.sortDescriptors = [sortDesc1,sortDesc2,sortDesc3]

return fetchRequest

}

func getFCR()-> NSFetchedResultsController {

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

return frc

}

因此,如图所示,我正在对Item执行获取请求实体,并按目录和部分实体中的属性排序。特别是针对我的问题,我在frc中将sections键作为Sections实体(与Catalog Entity相关联)中的section属性。



m更新Item或Catalog的各个部分时,我看到表格单元格正确更新(即,调用了didChangeObject事件)



但是,如果我更改了该节,除非我更改它完全退出桌子,然后重新进入。 (即即使更改了部分,也不会调用didChangeSection事件)



下面是我用来编辑现有项目记录的代码。

  func editItem(){

let item:Items = self.item!

item.qty =浮动(itemQty.text!)

item.catalog!.name = Util.trimSpaces(itemName.text!)
item.catalog !.brand = Util.trimSpaces(itemBrand.text!)
item.catalog!.qty = Float(itemQty.text!)
item.catalog!.price = Util.currencyToFloat(itemPrice.text! )
item.catalog!.size = Util.trimSpaces(itemSize.text!)
item.catalog!.image = UIImageJPEGRepresentation(itemImage.image !, 1)

如果(self.section!= nil){
item.catalog!.sections = self.section
}

do {
试试moc.save()
} catch {
fatalError(编辑项目保存失败)
}

if(itemProtocal!= nil){
itemProtocal!.finishedEdittingItem(self, item:self.item!)
}

}

只是要注意,当我在项实体中添加新记录时,didChangeObject和didChangeSection事件均被正确调用。只有在编辑它们时,didChangeSection才会被跳过或错过。



仅为了完成,下面是我用于didChangeObject和didChangeSection的代码。

  func controllerWillChangeContent(controller:NSFetchedResultsController){

tableView.beginUpdates()

}

func controllerDidChangeContent(controller:NSFetchedResultsController){

tableView.endUpdates()

}

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

开关类型{
case NSFetchedResultsChangeType.Update:
self.tableView.reloadSections(NSIndexSet(index: sectionIndex),withRowAnimation:UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Delete:
self.tableView.deleteSections(NSIndexSet(index:sectionInde x),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)
}

}

函数控制器(控制器:NSFetchedResultsController,didChangeObject anObject:AnyObject,atIndexPath indexPath:NSIndexPath ?, forChangeType类型:NSFetchedResultsChangeType,newIndexPath:NSIndexPath?){

开关类型{
case NSFetchedResultsChangeType.Update:
self.tableView.reloadRowsAtIndexPaths([indexPath!],withRowAnimation:UITableViewRowAnimation.Automatic)
case NSFetch edResultsChangeType.Delete:
self.tableView.deleteRowsAtIndexPaths([indexPath!],withRowAnimation:UITableViewRowAnimation.Automatic)
case NSFetchedResultsChangeType.Insert:
self.tableView.insertRowsAtIndexPaths([newIndexow!], :UITableViewRowAnimation.Fade)
case NSFetchedResultsChangeType.Move:
self.tableView.deleteRowsAtIndexPaths([indexPath!],withRowAnimation:UITableViewRowAnimation.Automatic)
self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation:UITableViewRowAnimation.Automatic)
}

}

何时我搜索了这个问题,发现其他人也遇到了类似的问题,这似乎是frc的功能(或错误)以及Xcode如何处理关系。基本上,frc只是监视项目实体,而当Section Entity更改时,它不会在frc中注册。人们也提出了各种黑客手段,但到目前为止,似乎没有一个对我有用。示例将执行以下操作: item.catalog.sections = item.catalog.sections
没有一个示例将section键作为相关实体,因此我我不确定这是否就是为什么他们不为我工作。



所以我的问题是,是否有某种方法可以告诉didChangeSection执行并正确发送NSFetchedResultsChangeType?甚至更好的是,是否有某种方法可以鼓励 frc注意到通过目录实体与项目实体相关的部分实体中发生了什么。

解决方案

稍作研究后,似乎只有在 didChangeSection > sectionNameKeyPath 是直接修改的(即,在这种情况下,如果您创建一个新的 Catalog 链接到正确的部分,并设置 item.catalog = newCatalog )。但是我认为这太复杂了。



一种解决方案是更改您的FRC来获取目录对象而不是 Items 。由于它们映射一对一,因此表视图应保留相同的结构。关键更改为:

  func fetchRequest()-> NSFetchRequest {

let fetchRequest = NSFetchRequest(entityName: Catalog)
let sortDesc1 = NSSortDescriptor(key: sections.section,升序:true)
let sortDesc2 = NSSortDescriptor (键:名称,升序:true)
fetchRequest.sortDescriptors = [sortDesc1,sortDesc2]

return fetchRequest
}

  func getFCR()-> NSFetchedResultsController {

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

返回frc

}

然后将引用修改为 frc 以反映此更改:

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

let cell = tableView.dequeueReusableCellWithIdentifier( cell,forIndexPath:indexPath)为! TableViewCell
让目录:Catalog = frc.objectAtIndexPath(indexPath)为!目录

cell.nameLbl.text =项目#\(catalog.name!)
cell.qtyLbl.text =数量:\(catalog.items.qty!。 stringValue)

返回单元格
}

 重写func tableView(tableView:UITableView,didSelectRowAtIndexPath indexPath:NSIndexPath){

让目录:Catalog = frc .objectAtIndexPath(indexPath)为!目录

var数量:Int = Int(catalog.items.qty!)
数量=数量+ 1
catalog.items.qty =数量

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

var sec:Int = Int(catalog.sections。 section!)
sec = sec + 1
var section:节?
if(checkSectionName(sec,moc:self.moc)== false){
让entityDesc = NSEntityDescription.entityForName( Sections,inManagedObjectContext:self.moc)
section = Sections(实体:entityDesc!,insertIntoManagedObjectContext:self.moc)

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

catalog.sections =部分

do {
try moc.save()
} catch {
fatalError(编辑项目保存失败)
}

}

因为您正在直接修改目录对象的部分属性,这将触发 didChangeSection 方法。在我看来,这仍然有点像骇客,但由于FRC的运行方式不尽人意,因此骇客可能是必不可少的邪恶。


Below is a link to download a simplified version of my app that has the exact same problem. The plus "Add" button at the top adds a new record that is set at name = 1, qty = 1, and section = 1. Selecting a Cell increments them all to the next number. You can see that both the name and qty update, but the section never updates until you quit the app and start it again. DropBox Download Link

I have the following relationship setup in CoreData:

In in my TableViewController, I am creating my FetchRequestController (frc) with the following code:

func fetchRequest() -> NSFetchRequest {

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

    return fetchRequest

}

func getFCR() -> NSFetchedResultsController {

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

    return frc

}

So as shown, I'm preforming the fetch request on the Item Entity, and sorting by attributes in both the Catalog and Sections entities. And specifically to my problem, I have the sections key in my frc as the section attribute in the Sections Entity (which is related through the Catalog Entity).

When I'm updating various parts of the Item or Catalog I see the table cell update correctly (i.e. the didChangeObject event is called)

But if I change the section it never updates unless I completely back out of the table and then reenter it. (i.e. the didChangeSection event is never called even though the section is changing)

Below is the code I'm using to edit a pre-existing Item Record.

func editItem() {

    let item: Items = self.item!

    item.qty = Float(itemQty.text!)

    item.catalog!.name = Util.trimSpaces(itemName.text!)
    item.catalog!.brand = Util.trimSpaces(itemBrand.text!)
    item.catalog!.qty = Float(itemQty.text!)
    item.catalog!.price = Util.currencyToFloat(itemPrice.text!)
    item.catalog!.size = Util.trimSpaces(itemSize.text!)
    item.catalog!.image = UIImageJPEGRepresentation(itemImage.image!, 1)

    if (self.section != nil) {
        item.catalog!.sections = self.section
    }

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

    if (itemProtocal != nil) {
        itemProtocal!.finishedEdittingItem(self, item: self.item!)
    }

}

Just to note, when I add in a new record into the Item Entity, the didChangeObject and didChangeSection events are both properly called. Only when editing them is didChangeSection getting skipped or missed.

Just for completion, below is my code I'm using for didChangeObject and didChangeSection.

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.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
        self.tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: UITableViewRowAnimation.Automatic)
    }

}

When I googled this issue, I found that others have had problems similar to this and it seems to be a feature (or bug) of the frc and how Xcode handles relationships. Basically, the frc is only watching the Item Entity, and when the Section Entity changes, it doesn't register with the frc. People have suggested various hacks as well, but so far none of them seem to be working for me. Examples are to do something like this item.catalog.sections = item.catalog.sections None of the examples had the section key as a related entity, so I'm not sure if that is why they aren't working for me.

So my question is if is there some way to tell didChangeSection to execute and send it the proper NSFetchedResultsChangeType? Or even better yet, is there some way to "encourage" the frc to notice what is happening in the Section Entity that is related to the Item Entity through the Catalog Entity.

解决方案

After playing with this a little, it seems the didChangeSection is only fired if the first relationship named in the sectionNameKeyPath is directly modified (ie. in this case, if you create a new Catalog linked to the correct section, and set item.catalog = newCatalog). But I think that is too convoluted as a work-around.

One solution would be to change your FRC to fetch the Catalog objects instead of Items. Since they map one-one, the table view should retain the same structure. The key changes are:

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
}

and

func getFCR() -> NSFetchedResultsController {

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

    return frc

}

Then modify the references to frc to reflect this change:

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
}

and

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

}

Because you are directly modifying the sections property of the catalog object, this will trigger the didChangeSection method. This still feels to me like a bit of a hack, but since the FRC is not behaving as one would like, a hack might be a necessary evil.

这篇关于未从相关实体快速调用节更新事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆