更新核心数据对象顺序-不起作用 [英] Update Core Data Object Order - Not Working
问题描述
当前行为
我的核心数据跟踪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 $ c $的对象c>或使用
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屋!