在看似随机的列表位置插入 CoreData 对象

Posted

技术标签:

【中文标题】在看似随机的列表位置插入 CoreData 对象【英文标题】:CoreData Object Inserted at Seemingly Random List Position 【发布时间】:2015-08-20 22:46:18 【问题描述】:

我在单独的视图中有两个表,每个表的列表在 CoreData 中都有一个单独的实体。用户可以点击任何单元格中的按钮将其移动到另一个列表。这很有效,只需点击一下即可移动项目,所有内容都会在应用关闭后保存并持续存在。

问题

目前,代码应该计算目标列表中的项目,然后将要移动的项目附加到其新列表的末尾。这不会发生。相反,该项目是随机插入的(不是在末尾或开头)。但是,一旦它被插入,任何进一步的移动项目都将直接位于它的下方。我尝试用 1 替换 count 函数,因为我真的希望移动的项目无论如何都显示在顶部,但这无济于事。

代码

首先,这是每次主视图出现时运行加载主列表的 viewDidLoad 代码:

  override func viewDidLoad() 
    super.viewDidLoad()

    currentListEntity = curList

    //Load the list from Core Data
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext!
    let fetchRequest = NSFetchRequest(entityName:  currentListEntity)
    let sortDescriptor = NSSortDescriptor(key: "displayOrder", ascending: true )
    fetchRequest.sortDescriptors = [ sortDescriptor ]
    var error: NSError?
    let fetchedResults = managedContext.executeFetchRequest(fetchRequest, error: &error) as? [NSManagedObject]


    if let results = fetchedResults 
        taskList_Cntxt = results
     else 
        println("Could not fetch \(error), \(error!.userInfo)")
    
 

我希望将移动的对象附加到新列表的末尾(这是实体参数)的功能,而是将其插入到其他列表项中:

func addToList (sender: AnyObject, entity: String) 
    //Setup CoreData context
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext!

    let entity =  NSEntityDescription.entityForName(entity, inManagedObjectContext: managedContext)
    let task = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)

    //Figure out the cell pressed
    let button = sender as! UIButton
    let contentView = button.superview!
    let cell = contentView.superview as! CustomTableViewCell_F2

    //Set cell contents to variables
    var nameValue = cell.nameLabel!.text
    var descValue = cell.descLabel!.text

    //Set content variables to NSObject called "task"
    task.setValue(nameValue, forKey: "name")
    task.setValue(descValue, forKey: "desc")

    //Error check
    var error: NSError?
    if !managedContext.save(&error) 
        println("Could not save \(error), \(error?.userInfo)")
    
    //Get count, append to end, sort, save
    var insertAt = taskList_Cntxt.count
    addTask(task, displayOrder: insertAt)
    updateDisplayOrder()
    managedContext.save(nil)

//Referenced by larger add-task function
func addTask( task: NSManagedObject, displayOrder: Int ) 
    taskList_Cntxt.insert( task, atIndex: displayOrder )
    updateDisplayOrder()


//Called to update Core Data after append, delete, and drag/drop
func updateDisplayOrder() 
    for i in 0..<taskList_Cntxt.count 
        let task = taskList_Cntxt[i]
        task.setValue( i, forKey: "displayOrder" )
    

关于如何解决这个问题的任何想法?理想情况下附加到列表的顶部,但此时将其附加到底部也很好。

【问题讨论】:

您似乎正在将任务添加到您的函数addTask 中的列表中,而您没有包括该列表。另外updateDisplayOrder 听起来肯定会影响显示顺序,但也不包括在内。几乎可以肯定,这两者对于正确订购都至关重要。 @TomHarrington 很抱歉,在熬夜后发布了这篇文章,试图解决这个问题和另一个问题,显然需要睡觉!我已经包含了这两个函数 【参考方案1】:

我终于弄明白了!

之前,当我使用该应用程序并查看列表并点击“移动到 x 列表”以获取项目时,该项目将被添加到中间某处的目标列表中。

现在,修复它之后,将任务从一个列表添加到另一个列表效果很好,当我加载目标列表时,我发送的项目始终位于顶部。

解决方案

如果您查看我的代码,我实际上所做的是提供了错误的插入地址。错误出现在两个地方。

错误 1

我正在获取旧列表的计数并将计数用作我的插入位置:

//Get count, append to end, sort, save
var insertAt = taskList_Cntxt.count
addTask(task, displayOrder: insertAt)
updateDisplayOrder()
managedContext.save(nil)

现在我已将方法更改为始终在 1 处插入:

var insertAt = 1
addTask(task, displayOrder: insertAt)
update_TargetDisplayOrder()
managedContext.save(nil)

错误 2

当我重新编号列表时,我更新了错误的列表:

func updateDisplayOrder() 
    for i in 0..<taskList_Cntxt.count 
        let task = taskList_Cntxt[i]
        task.setValue( i, forKey: "displayOrder" )

现在我将我的 add 函数指向一个查看目标列表而不是源列表的更新方法:

func update_TargetDisplayOrder() 
    for i in 0..<targetList_Cntxt.count 
        let task = targetList_Cntxt[i]
        task.setValue( i, forKey: "displayOrder" )
    

为了做到这一点,我需要添加第二个上下文变量。添加 targetList_Cntxt 允许我重新排序新列表而不是旧列表。在我这样做之后,一切正常。

注意

添加功能运行后,该项目从旧列表中删除:

func codeForDelete(sender: AnyObject) 
    //Figure out the cell pressed
    let cell = sender as! CustomTableViewCell
    let indexPath = tableView.indexPathForCell(cell)

    //Setup variables for CoreData delete methods
    let appDel: AppDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let context: NSManagedObjectContext = appDel.managedObjectContext!

    //Remove the deleted item from the model
    context.deleteObject(taskList_Cntxt[indexPath!.row] as NSManagedObject)
    taskList_Cntxt.removeAtIndex(indexPath!.row)
    context.save(nil)

    viewDidLoad()
    println("Delete task function ran")

但是当我写这篇文章时,我意识到我遗漏了一个函数来更新旧列表的排序顺序,一旦我执行删除。这是我可能需要解决的问题!

【讨论】:

以上是关于在看似随机的列表位置插入 CoreData 对象的主要内容,如果未能解决你的问题,请参考以下文章

Core Data 中看似有效的对象出现“悬空引用无效对象”错误

插入对象——核心数据

RestKit / CoreData:两次请求相同的URL时插入重复的对象而不是合并

MYSQL 从列表中随机插入

C++Primer 第九章

顺序容器----顺序容器概述,容器库概览