更新核心数据对象顺序 - 不起作用

Dav*_*e G 3 core-data uitableview swift

当前行为

我的核心数据跟踪UITableView列表的值.每行都有标题和说明.我的核心数据用于追加新记录,然后删除它们.核心数据也非常适合编辑现有记录的内容.

问题/疑问

我刚刚在表格中添加了拖放功能.从表面上看,它完美无缺.我可以将顶部项目拖动到底部,从中间到顶部等.但是,由于核心数据记录未更新,因此新的列表顺序在应用程序关闭后不会保留.

我找到了一些关于此的教程,但似乎没有一个与我的代码一起使用.我还花了几个小时试图使用和调整我当前的核心数据技能集(更新,删除,编辑)来发明一个解决方案.我没有甜蜜的动作或代码功夫.

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

信息

在Swift中编码

使用X-Code 6.4

核心数据信息:

文件名是:CD_Model

实体名称:TodayTask

属性名称:"name"和"desc"

码:

主列表变量:

var todayTaskList = [NSManagedObject]()
Run Code Online (Sandbox Code Playgroud)

使用UITableView的主列表页面的ViewDidLoad

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)
}
Run Code Online (Sandbox Code Playgroud)

表设置

//***** ----- ***** ------ ***** ----- ***** ----- *****
//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
}
Run Code Online (Sandbox Code Playgroud)

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

   //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
                        }
                })
        }
Run Code Online (Sandbox Code Playgroud)

我很确定我需要的代码会进入第二个case语句:

case UIGestureRecognizerState.Changed:
Run Code Online (Sandbox Code Playgroud)

我也认为我需要的代码会从......开始.

var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as! AppDelegate)
var context: NSManagedObjectContext = appDel.managedObjectContext!
Run Code Online (Sandbox Code Playgroud)

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

非常感谢能够帮助解决这个问题的任何人!

Pat*_*nch 7

首先,您可能会发现为每个实体创建类更容易,这样您就不必使用模糊键入NSManagedObject或读取和转换的对象valueForKey(_:).在下面的解决方案中,我已经包含了代码示例.

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

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

在此输入图像描述

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 ]
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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

class Task: NSManagedObject {
    @NSManaged var name: NSString
    @NSManaged var desc: NSString
    @NSManaged var parentList: TaskList?
}
Run Code Online (Sandbox Code Playgroud)

更新以回答剩余的问题:

我强烈建议您使用自己的自定义类而不是NSManagedObject,但直到您在这里找到该部分,您可以对代码执行的操作.

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

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

要附加新任务:

func addTask( task: NSManagedObject, displayOrder: Int ) {
    todayTaskList.insert( task, atIndex: displayOrder )
    updateDisplayOrder()
}
Run Code Online (Sandbox Code Playgroud)