I have two tables in separate views, each table's list has a separate entity in CoreData. A user can tap a button within any cell to move it to the other list. This works, items can be moved at a single tap, everything is saved and persists after app shutdown.
Problem
Currently the code is supposed to count the items in the destination list, then append the item being moved to the end of its new list. This doesn't happen. Instead the item is randomly inserted (not at the end or beginning). However, once it is inserted, any further items move will be directly below it. I tried replacing the count function with 1, because I really want the moved item to show at the top anyway, but that doesn't help.
Code
First, here's the viewDidLoad code that runs the load the main list every time the main view appears:
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)")
}
}
Function that I would expect to append the moved object to the end of the new list (which is the entity parameter), but instead inserts it amongst other list items:
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" )
}
}
Any ideas on how to fix this? Ideally to append to the top of the list, but at this point appending it to the bottom would be great too.
I did eventually figure this out!
Before, when I was using the app and looking at the list and tapped 'move to x list' for an item, the item would be added to the destination list somewhere in the middle.
Now, after fixing it, adding a task from one list to another works great, when I load the destination list the item I sent is always sitting right on top.
The Solution
If you look at my code, what I was actually doing was giving the wrong insert address. The error was in two places.
Error 1
I was getting a count of the old list and using the count as my insert position:
//Get count, append to end, sort, save
var insertAt = taskList_Cntxt.count
addTask(task, displayOrder: insertAt)
updateDisplayOrder()
managedContext.save(nil)
Now I've changed the method to always insert at 1:
var insertAt = 1
addTask(task, displayOrder: insertAt)
update_TargetDisplayOrder()
managedContext.save(nil)
Error 2
When I was renumbering the list, I was updating the wrong list:
func updateDisplayOrder() {
for i in 0..<taskList_Cntxt.count {
let task = taskList_Cntxt[i]
task.setValue( i, forKey: "displayOrder" )
}
Now I point my add function to an update method that looks at the target list, not the source list:
func update_TargetDisplayOrder() {
for i in 0..<targetList_Cntxt.count {
let task = targetList_Cntxt[i]
task.setValue( i, forKey: "displayOrder" )
}
}
In order to do this, I needed to add a second context variable. Adding targetList_Cntxt allowed me to reorder the new list instead of the old one. After I did that, everything worked.
Note:
After the add function runs, the item is deleted from the old list:
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")
}
But as I write this I am realizing I am leaving out a function to update the sort order of the old list once I do the delete. That's something I might need to fix!