有没有办法通过按下条形按钮项目来更新核心数据模型中的对象?

问题描述

我的目标是在编辑文本后按下完成按钮来更新核心数据中的对象。

完成按钮和下面的文本字段:

enter image description here

这是我的一些代码

@objc func doneTapped() {

    
    do {
        try context.save()
    } catch {
        print("Error saving the new information \(error)")
    }
    
    dateEditableTextF.resignFirstResponder()
    selectedEventDate = dateEditableTextF.text
    dateEditableTextF.isEnabled = false
    
    costEditableTextF.resignFirstResponder()
    selectedEventCost = costEditableTextF.text
    costEditableTextF.isEnabled = false
    
    
    gradesEditableTextF.resignFirstResponder()
    selectedEventGrade = gradesEditableTextF.text
    gradesEditableTextF.isEnabled = false
    
    navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit,target: self,action: #selector(editTapped))
    
  
}

我希望当我在编辑文本字段后运行应用程序时按下完成按钮时,信息会更新,而当我返回到视图控制器时,信息会相同并且我的核心数据数据库会更新具有该对象的更新属性

实际发生的情况是,当我完成编辑文本字段时,视图控制器中的数据会更新,但是当我离开视图控制器并返回时,数据会恢复到旧条目。

我看了大约 4 个关于 crud 方法的 youtube 视频,它们都是不同的场景,与我的不匹配,所以我希望这里有人可以提供帮助。提前致谢。

这是我的视图控制器的其余部分。

    @IBOutlet weak var costEditableTextF: UITextField!
    @IBOutlet weak var dateEditableTextF: UITextField!
    @IBOutlet weak var gradesEditableTextF: UITextField!
    
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    
    
    var updateTheEvents = [Event]()
    
    var selectedEventName: String?
    var selectedEventDate: String?
    var selectedEventCost: String?
    var selectedEventGrade: String?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        
        navigationItem.title = selectedEventName
        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .edit,action: #selector(editTapped))
     
        
     
        
        if let datetoLoad = selectedEventDate {
            dateEditableTextF.text = selectedEventDate
        }
        
        if let costToLoad = selectedEventCost {
            costEditableTextF.text = selectedEventCost
        }
        
        if let gradesToLoad = selectedEventGrade {
            gradesEditableTextF.text = selectedEventGrade
        }

        // Do any additional setup after loading the view.
    }
    
    
   @objc func editTapped() {
    
   
    dateEditableTextF.becomeFirstResponder()
    dateEditableTextF.isEnabled = true
    costEditableTextF.isEnabled = true
    gradesEditableTextF.isEnabled = true
    navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done,action: #selector(doneTapped))
    
        
    }

解决方法

首先你需要创建一个存储来管理你的persistentContainer和CRUD操作:

class PersistenceManager {
lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "your_xcdatamodeld_name") //Here you should type the name of your xcdatamodeld file without the extension .xcdatamodeld
    container.loadPersistentStores(completionHandler: { (storeDescription,error) in
        if let error = error as NSError? {
            fatalError("Unresolved error \(error),\(error.userInfo)")
        }
    })
    container.viewContext.automaticallyMergesChangesFromParent = true
    container.viewContext.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
    return container
}()
}

现在要保存数据,您需要一个上下文。我强烈建议你使用全局的。我在从外部函数访问商店上下文时遇到了几个问题(即没有添加/编辑东西)。请注意,尽管它对我很有用,但我不确定全局上下文是否是最佳实践。不过,我还遇到了任何问题。

在您的 PersistenceManager 类中,在persistentContainer 之前放置以下代码

static let shared = PersistenceManager()
var managedObjectContext: NSManagedObjectContext {
    persistentContainer.viewContext
}

并且,在课前和课外放以下内容

let context = PersistenceManager.shared.managedObjectContext
...
class PersistenceManager { [...] }

现在您必须像这样创建保存功能:

func saveContext () {
      if context.hasChanges {
          do {
              try context.save()
          } catch {
              let nserror = error as NSError
              fatalError("Unresolved error \(nserror),\(nserror.userInfo)")
          }
      }

这在 PersistenceManager 类中。

现在是有趣的部分:您必须创建 CRUD 函数。这些都将在您的 PersistenceManager 类中。我将向您展示一个关于创建和编辑实体的小演示。

假设您有一个名为“Item”的实体,它具有属性 name 和 price。
要保存每个项目,您将拥有如下功能:

func creaateNewItem(name: String,price: Int) -> Item {
        let entity = NSEntityDescription.entity(forEntityName: Item,in: context)
        let newItem = Item(entity: entity!,insertInto: context)
        
        newItem.name = name
        newItem.price = price
        
        self.saveContext()
        return newItem
    }

要编辑项目,您必须获取它,然后为其分配新值:

func editItem(currentItem: Item,newName: String,newPrice: Int) {
    
    let currentName: String = currentItem.name! //Current name
    
    //Looking for the item to edit
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Item")
    request.predicate = NSPredicate(format: "name = %@",currentName)
    request.returnsObjectsAsFaults = false
    
    do { //Editing the item
        let editedItem = (try context.fetch(request))[0] as! Item
        
        editedItem.name = newName
        editedItem.price = newPrice
       
        self.saveContext()
       
    } catch let error {
        print("Error \n \((error))")
    }
 
}

正如你在这里看到的,我传递了一些参数,允许你自定义你的项目。显然,如果您需要分配默认值,您可以删除这些参数。

现在,在您的视图控制器中,您将创建一个 Item 数组对象:

my item : [Item]? 

里面会装满你的物品。
要通过按条形按钮来编辑您保存的项目,您现在只需执行以下操作:

@objc func editMyItem(){
let newName = "Edited Item"
let newPrice = 15

PersistenceManager().editItem(currentItem: item[indexOfYourChoice],newName: newName,newPrice: newPrice)
}

您的项目将被编辑!
请注意,例如,如果您希望文本来自文本字段,则 newPrice 常量将等于该文本字段的文本。