swift - 编辑核心数据列表项追加而不是添加

标签 swift uitableview core-data edit objectcontext

我的待办事项应用程序已经具有添加和删除(从核心数据)功能。那很完美。我的问题是我添加编辑的尝试出现故障。

行为

我对其进行了编码,因此如果用户点击表中的任务,它会将该任务的单元格索引路径、标题和描述设置为变量,并将它们传递给模态 ViewController 进行编辑。模态视图呈现,然后那些传递的变量填充文本字段。然后用户可以编辑现有内容并点击保存,这会运行一些保存代码(我将在下面分享)。模态视图被关闭,表格数据重新加载,单元格出现在它之前的位置,但内容已更新。这一切都有效。故障发生在应用程序关闭/完全关闭并重新打开时。突然,原来的任务又回来了,但是经过编辑的副本被附加到列表的底部。

问题

为什么我的代码会这样,我如何才能正确保存和加载编辑后的标题和描述?

信息

我的核心数据文件名是:CD_Model 我的实体名称是:TodayTask 我的属性名称是:1) "name"2) "desc"

代码

我包含了很多我的代码,以防错误出现在我意想不到的地方。但是,我在我认为导致问题的两个片段的标题中添加了粗体。只有在 viewDidLoad 运行时才会显示错误(下面的第一个代码片段)。但错误实际上可能发生在最后一个代码段,即保存函数中。

导入和全局变量:

import UIKit
import CoreData

var todayTaskList = [NSManagedObject]()
var passingEdit = false

主VC的声明和viewDidLoad,其中包含表格:

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
//***** ----- ***** ------ ***** ----- ***** ----- *****
//Initial Setup
//***** ----- ***** ------ ***** ----- ***** ----- *****

@IBOutlet weak var tableView: UITableView!

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

    //This loads the list from Core Data
    //1
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext!

    //2
    let fetchRequest = NSFetchRequest(entityName:"TodayTask")

    //3
    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)")
    }

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

创建表的代码:

//***** ----- ***** ------ ***** ----- ***** ----- *****
//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
}

点击现有任务时运行的代码:

//***** ----- ***** ------ ***** ----- ***** ----- *****
//Functions
//***** ----- ***** ------ ***** ----- ***** ----- *****

//Action: Edit list item on row tap
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    passingEdit = true

    performSegueWithIdentifier("modalToEditor", sender: nil)
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "modalToEditor") && passingEdit == true {

        //Assign selection to a variable 'currentCell'
        let indexPath = tableView.indexPathForSelectedRow();
        let currentCell = tableView.cellForRowAtIndexPath(indexPath!) as! CustomTableViewCell;

        //Set cell text into variables to pass to editor
        var cellNameForEdit = currentCell.nameLabel!.text
        var cellDescForEdit = currentCell.descLabel.text

        //Pass values to EditorView
        var editorVC = segue.destinationViewController as! EditorView;
        editorVC.namePassed = cellNameForEdit
        editorVC.descPassed = cellDescForEdit
        editorVC.indexOfTap = indexPath


    }
}

modal Editor VC 的声明,从主 VC 传递的变量被设置:

class EditorView: UIViewController, UITextFieldDelegate {

//Declare outlets and vars
@IBOutlet var txtTask: UITextField!
@IBOutlet var txtDesc: UITextView!
@IBOutlet weak var addSave: UIButton!
@IBOutlet weak var cancel: UIButton!

var namePassed: String!
var descPassed: String!
var indexOfTap: NSIndexPath!

//Initial Functions
override func viewDidLoad() {
    super.viewDidLoad()

    self.txtTask.becomeFirstResponder()

    if passingEdit == true {
        txtTask.text = namePassed
        txtDesc.text = descPassed
        addSave.setTitle("Save", forState: UIControlState.Normal)
    }
    else {
        addSave.setTitle("Add", forState: UIControlState.Normal)
    }
}

函数在点击保存按钮时运行:

func modRec(nameValue: String, descValue: String, indexPos: NSIndexPath) {

    //1
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext!

    //2
    let entity =  NSEntityDescription.entityForName("TodayTask", inManagedObjectContext: managedContext)
    let todayTask = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)

    //3
    todayTask.setValue(nameValue, forKey: "name")
    todayTask.setValue(descValue, forKey: "desc")

    //4
    var error: NSError?
    if !managedContext.save(&error) {
        println("Could not save \(error), \(error?.userInfo)")
    }
    //5
    todayTaskList[indexPos.row] = todayTask
    managedContext.save(nil)


}

最佳答案

在您的 modRec 方法中,您创建了一个新的 TodayTask 对象:

let todayTask = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)

然后您替换todayTaskList 数组中相关索引处的对象:

todayTaskList[indexPos.row] = todayTask

但是您正在修改其值的前一个对象仍然存在。它不再在您的数组中,但它仍在 Core Data 存储中。当您重新加载您的 TableView 时,它使用 todayTaskList 数组来填充行,您会看到您所期望的。但是,当您关闭并重新打开应用程序时,todayTaskList 数组本身会通过从 CoreData 存储中获取来重建。因为旧的 todayTask 和新的都存在,所以它们都被添加到数组中,因此您的 TableView 会显示两者。

要解决这个问题,我会稍微重组您的代码:

  1. 修改 EditorView View Controller :不是为传递给它的每个属性都使用 var,而是为完整的 NSManagedObject 使用 var。然后,您可以使用该 NSMO 的属性填充文本字段。 (您需要相应地修改 prepareForSegue 代码。如果您要添加新的 TodayTask,则创建 NSManagedObject,并将其添加到您的数组中,然后再转到 EditorView)。
  2. 然后,在您的modRec 方法中,您无需插入新的TodayTask 对象,只需设置NSMO 变量的属性即可。
  3. 由于您修改现有的 NSMO,而不是插入一个新的,因此您不需要替换 todayTaskList 数组中的对象。

因为您不再需要从 EditorView 中更新 todayTaskList 数组,所以它不需要是全局的(作为一种好的做法,您应尽可能避免这样做)。它可以只是你主视图 Controller 中的一个变量。 (也应该可以避免 passingEdit 是全局的)。

关于swift - 编辑核心数据列表项追加而不是添加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31889941/

相关文章:

objective-c - 消失的 NSMutableArray,导致 UiTableView 显示空白单元格

objective-c - NSPredicate 表达式过滤一对多关系的计数

ios - NSFetchedResultsController 与 NSPredicate

ios - 乘以文本字段错误?

ios - swift fatal error : unexpectedly found nil while unwrapping an Optional value (lldb) in Tableview

ios - 在 Swift 中使用 FMDB 回滚事务

ios - 从 xml 预加载数据, TableView 不会重新加载

ios - 将数组保存到核心数据

swift - RxSwift 取消 RxMoya 网络请求

iOS VPN 一段时间后自动断开连接