更新核心数据对象顺序-不起作用 [英] Update Core Data Object Order - Not Working

查看:73
本文介绍了更新核心数据对象顺序-不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当前行为

我的核心数据跟踪UITableView列表的值。每行都有标题和描述。我的核心数据用于附加新记录,并在以后删除它们。核心数据对于编辑现有记录的内容也非常有用。

My core data keeps track of the values for a UITableView list. Each row has a title and description. My core data is working for appending new records and later deleting them. Core data is also working great for editing the content of the existing records.

问题/问题

我刚刚在表中添加了拖放功能。从表面上看,它运行完美。我可以将顶部的项目拖到底部,在中间的顶部等。但是,由于未更新Core Data记录,因此新的列表顺序在应用关闭后不会保留。

I just added drag and drop functionality in the table. On the surface, it works perfectly. I can drag the top item to the bottom, middle to the top, etc. However, the new list order does not persist after app shutdown because the Core Data records aren't being updated.

我找到了一些有关此的教程,但似乎没有一个适合我的代码。我还花了几个小时来尝试使用和适应当前的核心数据技能(更新,删除,编辑)来发明解决方案。我没有甜言蜜语或功夫代码。

I found a few tutorials on this but none seem to work with my code. I also spent a few hours trying to use and adapt my current Core Data skill set (update, delete, edit) to invent a solution. I have no sweet moves or code kung fu.

您应该选择接受此任务,以下是您可能需要的详细信息和代码。

Should you choose to accept this mission, below are the details and code you might need.

信息

Swift编码

使用X代码6.4

核心数据信息:

文件名是:CD_Model

File name is: CD_Model

实体名称:TodayTask

Entity name: TodayTask

属性名称:名称和 desc

Attribute names: "name" and "desc"

代码:

主列表变量:

var todayTaskList = [NSManagedObject]()

使用UITableView的主列表页面的ViewDidLoad

ViewDidLoad for main list page with UITableView

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    //Break

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

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

    //Break

    //This provides a variable height for each row
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 80.0

    //Break

    //Part of code for cell drag and drop functionality
    let longpress = UILongPressGestureRecognizer(target: self, action: "longPressGestureRecognized:")
    tableView.addGestureRecognizer(longpress)
}

表格设置

//***** ----- ***** ------ ***** ----- ***** ----- *****
//Table View & Cell Setup
//***** ----- ***** ------ ***** ----- ***** ----- *****
@IBOutlet weak var name_Label: UILabel!
@IBOutlet weak var desc_Label: UILabel!

//Tells the table how many rows it should render
//*Looks to the Core Data NSObject to count tasks
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return todayTaskList.count
}

//Creates the individual cells. If the above function returns 3, this runs 3 times
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    //Setup variables
    let cellIdentifier = "BasicCell"
    let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as! CustomTableViewCell
    let task = todayTaskList[indexPath.row]

    //Create table cell with values from Core Data attribute lists
    cell.nameLabel!.text = task.valueForKey("name") as? String
    cell.descLabel!.text = task.valueForKey("desc") as? String

    //Make sure the row heights adjust properly
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 80.0

    return cell
}

这就是我的问题所在,即拖放。此代码有效,但是缺少重新排列核心数据的代码。如果没有该代码,当我缩小差距时,任何拖放重新排序都将重置:

And here is where my problem is, the drag and drop. This code works, but it is missing code that rearranges the core data. Without that code, any drag/drop re-ordering will reset when I close the gap:

   //This function initiates the Drag & Drop code.
    func longPressGestureRecognized(gestureRecognizer: UIGestureRecognizer) {

        let longPress = gestureRecognizer as! UILongPressGestureRecognizer
        let state = longPress.state

        var locationInView = longPress.locationInView(tableView)
        var indexPath = tableView.indexPathForRowAtPoint(locationInView)

        struct My {
            static var cellSnapshot : UIView? = nil
        }
        struct Path {
            static var initialIndexPath : NSIndexPath? = nil
        }

        let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! CustomTableViewCell;

        var dragCellName = currentCell.nameLabel!.text
        var dragCellDesc = currentCell.descLabel.text


        //Steps to take a cell snapshot. Function to be called in switch statement
        func snapshopOfCell(inputView: UIView) -> UIView {
            UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0.0)
            inputView.layer.renderInContext(UIGraphicsGetCurrentContext())
            let image = UIGraphicsGetImageFromCurrentImageContext() as UIImage
            UIGraphicsEndImageContext()
            let cellSnapshot : UIView = UIImageView(image: image)
            cellSnapshot.layer.masksToBounds = false
            cellSnapshot.layer.cornerRadius = 0.0
            cellSnapshot.layer.shadowOffset = CGSizeMake(-5.0, 0.0)
            cellSnapshot.layer.shadowRadius = 5.0
            cellSnapshot.layer.shadowOpacity = 0.4
            return cellSnapshot
        }


        switch state {
            case UIGestureRecognizerState.Began:
                //Calls above function to take snapshot of held cell, animate pop out
                //Run when a long-press gesture begins on a cell
                if indexPath != nil {
                    Path.initialIndexPath = indexPath
                    let cell = tableView.cellForRowAtIndexPath(indexPath!) as UITableViewCell!
                    My.cellSnapshot  = snapshopOfCell(cell)
                    var center = cell.center

                    My.cellSnapshot!.center = center
                    My.cellSnapshot!.alpha = 0.0

                    tableView.addSubview(My.cellSnapshot!)

                    UIView.animateWithDuration(0.25, animations: { () -> Void in
                        center.y = locationInView.y

                        My.cellSnapshot!.center = center
                        My.cellSnapshot!.transform = CGAffineTransformMakeScale(1.05, 1.05)
                        My.cellSnapshot!.alpha = 0.98

                        cell.alpha = 0.0

                        }, completion: { (finished) -> Void in

                            if finished {
                                cell.hidden = true
                            }
                    })
                }
            case UIGestureRecognizerState.Changed:
                //Runs when the user "lets go" of the cell
                //Sets CG Y-Coordinate of snapshot cell to center of current location in table (snaps into place)
                //If the indexPath is not 0 AND is not the same as it began (didn't move)...
                //Update array and table row order
                var center = My.cellSnapshot!.center
                center.y = locationInView.y
                My.cellSnapshot!.center = center
                if ((indexPath != nil) && (indexPath != Path.initialIndexPath)) {

                    swap(&todayTaskList[indexPath!.row], &todayTaskList[Path.initialIndexPath!.row])
                    tableView.moveRowAtIndexPath(Path.initialIndexPath!, toIndexPath: indexPath!)

                    Path.initialIndexPath = indexPath

                }
            default:
                //Runs continuously as there's a long press recognized?
                //Animates cell movement
                //Completion block: 
                //Removes snapshot of cell, cleans everything up
                let cell = tableView.cellForRowAtIndexPath(Path.initialIndexPath!) as UITableViewCell!
                cell.hidden = false
                cell.alpha = 0.0
                UIView.animateWithDuration(0.25, animations: { () -> Void in
                    My.cellSnapshot!.center = cell.center
                    My.cellSnapshot!.transform = CGAffineTransformIdentity
                    My.cellSnapshot!.alpha = 0.0
                    cell.alpha = 1.0
                    }, completion: { (finished) -> Void in
                        if finished {
                            Path.initialIndexPath = nil
                            My.cellSnapshot!.removeFromSuperview()
                            My.cellSnapshot = nil
                        }
                })
        }

我很确定我需要的代码会出现在第二个case语句中:

I am pretty sure the code I need would go inside the second case statement:

case UIGestureRecognizerState.Changed:

我也认为我需要从以下内容开始...

I also think the code I need would start with something like...

var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!

但是,是否有用于重新排列的特殊代码?我必须删除并插入吗?如果是这样,怎么办?

But then is there a special code for rearranging? Do I have to delete and insert? If so, how?

感谢所有能帮助解决这一问题的人!

HUGE thanks in advance to anyone who can help resolve this one!

推荐答案

首先,您可能会发现为每个实体创建类更加容易,这样您就不必使用含糊不清地键入 NSManagedObject 或使用 valueForKey(_:)进行投射和投射。在下面的解决方案中,我包括了代码示例。

Well first of all, you might find it easier to create classes for each entity so that you don't have to work with objects vaguely typed to NSManagedObject or read and cast with valueForKey(_:). In the solution below, I've included code samples for that.

因此,要解决您的订单问题,您可以做两件事:

So to solve your order problem, there are two things you could do:

1)添加一个属性,该属性定义 Task 实体的顺序。这很简单,就像 NSNumber 称为 displayOrder 一样。然后,您的提取请求可以根据该属性对结果进行排序。然后,在重新排列表格单元格时,遍历任务列表并更新每个任务的 displayOrder 属性以反映它们的显示顺序。保存您的托管对象上下文,并在下次提取请求加载时对其进行相应排序。

1) Add a property that defines the order of your Task entity. This can be a simple as an NSNumber called displayOrder. Your fetch request can then order the results according to that property. Then, when your table cells are re-arranged, iterate through the task list and update the displayOrder property of each task to reflect the order in which they are being displayed. Save your managed object context and the next time your fetch request loads, it will order them accordingly.

class Task: NSManagedObject {
    @NSManaged var name: NSString
    @NSManaged var desc: NSString
    @NSManaged var displayOrder: NSNumber
}

let fetchRequest = NSFetchRequest()
let sortDescriptor = NSSortDescriptor(key: "displayOrder", ascending: true )
fetchRequest.sortDescriptors = [ sortDescriptor ]

2)创建一个CoreData实体,该实体表示具有多对多关系的列表将每个任务实体存储在有序集合中。然后,当您将任务添加到集合中时,它们将按照添加任务的顺序保存。

2) Create a CoreData entity that represents a list with a to-many relationship that stores each task entity in an ordered set. Then, when you add tasks to the set, they will be remain saved in the order you've added them.

class TaskList: NSManagedObject {
    @NSManaged var tasks: NSOrderedSet?
}

class Task: NSManagedObject {
    @NSManaged var name: NSString
    @NSManaged var desc: NSString
    @NSManaged var parentList: TaskList?
}

更新以回答其余问题:

我强烈建议您使用自己的自定义类,而不要使用 NSManagedObject ,但是直到您找出一部分,这是您可以做的

I highly recommend you use your own custom classes instead of NSManagedObject, but until you figure that part out here's what you can do to your code as is.

在重新排列或删除后更新显示顺序:

To update display order after rearranging or deleting:

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

要追加新任务:

func addTask( task: NSManagedObject, displayOrder: Int ) {
    todayTaskList.insert( task, atIndex: displayOrder )
    updateDisplayOrder()
}

这篇关于更新核心数据对象顺序-不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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