How do you update a CoreData entry that has already been saved in Swift?

后端 未结 14 2598
有刺的猬
有刺的猬 2020-11-30 00:55

I\'m not sure what I\'m doing wrong here, but when I save the first time into coredata, it works just fine. When I try to overwrite that, it doesn\'t.

func t         


        
相关标签:
14条回答
  • 2020-11-30 01:29

    //For Swift UI inside the view outside the body :)
    @Environment(.managedObjectContext) var managedObjectContext

    var isNewRecord = false
        let aNewContact: Contact!
          
        let fetchConcact: NSFetchRequest<Contact> = Contact.fetchRequest() as! NSFetchRequest<Contact>
        
        fetchConcact.predicate = NSPredicate(format: "record_id == %@", contactRemoteModel.contacts[i].record_id as CVarArg)
             
        let results = try? managedObjectContext.fetch(fetchConcact)
        
          if results?.count == 0 {
          // here you are inserting
          aNewContact = Contact(context: managedObjectContext)
          aNewContact.id = UUID()
          isNewRecord = true
                 print("Insert")
          } else {
             // here you are updating
              aNewContact = results?.first
              print("UpDate")
          }
    
    0 讨论(0)
  • 2020-11-30 01:30

    This worked for me. First i set filter by given attribute "taskName" with fetchRequest.predicate. Then i fetch data that already been saved and set value for "status" to update that object.

    func updateTaskStatus(status: Bool){
    
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest: NSFetchRequest<Task> = Task.fetchRequest()
        let predicate = NSPredicate(format: "(taskName = %@)", (task?.taskName)!)
        fetchRequest.predicate = predicate
        do {
            let result = try managedContext.fetch(fetchRequest)
            task = result[0] as NSManagedObject as? Task
            task?.setValue(status, forKey: "status")
            do {
                try managedContext.save()
            }catch  let error as NSError {
                print("\(error)")
            }
        }catch let error as NSError {
            print("\(error)")
        }
    }
    
    0 讨论(0)
  • 2020-11-30 01:31

    Swift >= 2 the method now returns a non-optional and throws an error in the error case, which must be handled with try-catch:

        let context = self.fetchedResultsController.managedObjectContext
        let entity = self.fetchedResultsController.fetchRequest.entity!
    
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName:entity.name!)
        fetchRequest.predicate = NSPredicate(format: "notificationId = 13")
    
        do {
            let list = try context.executeFetchRequest(fetchRequest) as? [NSManagedObject]
            if list!.count == 0 // Check notificationId available then not save
            {
                let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName(entity.name!, inManagedObjectContext: context)
                newManagedObject.setValue("This is first message13", forKey: "message")
                newManagedObject.setValue(1, forKey: "appId")
                newManagedObject.setValue(13, forKey: "notificationId")
                newManagedObject.setValue("First one", forKey: "tital")
            }
            // success ...
        } catch let error as NSError {
            // failure
            print("Fetch failed: \(error.localizedDescription)")
        }
    
    0 讨论(0)
  • 2020-11-30 01:39

    Updated for Swift 4 & XCode 9.2

    To answer your question...

    How do you update a CoreData entry that has already been saved in Swift?

    You first need to get a reference to your AppDelegate and viewContext. You then need to set up a NSFetchRequest for the Entity you are looking to update, in my example that would be "Alert". You then set up your fetch to find the result you are looking for. In the example, my result found Alerts by their creation date and alert type.

    To further read how to query using a predicate. Stack Overflow Example & Apple Documentation

    I then context.fetch(fetchRequest), set the results to the value I wanted to update, and dealt with errors in a try catch. Finally I context.save().

    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Alert")
    
    fetchRequest.predicate = NSPredicate(format: "creationDate = %@ AND alertType = %&",
                                             argumentArray: [creationDate, alertType])
    
    do {
        let results = try context.fetch(fetchRequest) as? [NSManagedObject]
        if results?.count != 0 { // Atleast one was returned
    
            // In my case, I only updated the first item in results
            results[0].setValue(yourValueToBeSet, forKey: "yourCoreDataAttribute")
        }
    } catch {
        print("Fetch Failed: \(error)")
    }
    
    do { 
        try context.save() 
       }
    catch {
        print("Saving Core Data Failed: \(error)")
    }
    
    0 讨论(0)
  • 2020-11-30 01:39

    Step:1 - create new project and select "Use Core Data" go through : "https://medium.com/@ankurvekariya/core-data-crud-with-swift-4-2-for-beginners-40efe4e7d1cc"

    Step:2 - Inside ViewController (userList)

    import UIKit
    import CoreData
    
    class ViewController: UIViewController, UITableViewDelegate , UITableViewDataSource {
    
    var arrUser = Array<Any>()
    @IBOutlet var tableView: UITableView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.title = "User List"
        self.tableView.separatorStyle = .none
        self.retrieveData(Delete: false, indexpath: 0)
    
        let logoutBarButtonItem = UIBarButtonItem(image: UIImage(named: "addImage"), style: .done, target: self, action: #selector(addNewUser))
        self.navigationItem.rightBarButtonItem  = logoutBarButtonItem
    }
    
    override func viewDidAppear(_ animated: Bool)
    {
        super.viewDidDisappear(animated)
        self.retrieveData(Delete: false, indexpath: 0)
    }
    
    @objc func addNewUser(){
        let userVC = self.storyboard?.instantiateViewController(withIdentifier: "AddUser_VC") as! AddUser_VC
        self.navigationController?.pushViewController(userVC, animated: true)
    }
    
    //MARK: - TableView DataSource Delegate
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.arrUser.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
        let cell = tableView.dequeueReusableCell(withIdentifier: "UserCell") as! UserCell
        cell.selectionStyle = .none
        let dictData = self.arrUser[indexPath.row] as? NSManagedObject
        cell.lblName.text = dictData?.value(forKey: "name") as? String ?? ""
        cell.lblPost.text = dictData?.value(forKey: "post") as? String ?? ""
        cell.lblEmail.text = dictData?.value(forKey: "email") as? String ?? ""
        cell.lblPhone.text = String(dictData?.value(forKey: "phone") as? Int ?? 0)
        cell.imageData?.image =  UIImage(data: dictData?.value(forKey: "image") as? Data ?? Data())
    
        return cell
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 140
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    
        let dictData = self.arrUser[indexPath.row] as? NSManagedObject
        let AddUserVC = self.storyboard?.instantiateViewController(withIdentifier: "AddUser_VC") as! AddUser_VC
        AddUserVC.isEdit  = true
        AddUserVC.dictObj = dictData
        self.navigationController?.pushViewController(AddUserVC, animated: true)
    
    }
    
    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if (editingStyle == .delete) {
            //self.deleteData(indexpath: indexPath.row)
            self.retrieveData(Delete: true, indexpath: indexPath.row)
        }
    }
    
    //MARK: - retrieveData
    func retrieveData(Delete:Bool , indexpath:Int) {
    
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "UserTable")
    
        if (Delete == true)
        {
            do
            {
                let test = try managedContext.fetch(fetchRequest)
    
                let objectToDelete = test[indexpath] as! NSManagedObject
                managedContext.delete(objectToDelete)
    
                do{
                    try managedContext.save()
                    self.retrieveData(Delete: false, indexpath: 0)
                }
                catch
                {
                    print(error)
                }
            }
            catch
            {
                print(error)
            }
        }
    
        do {
            self.arrUser = try managedContext.fetch(fetchRequest)
            self.tableView.reloadData()
            print(self.arrUser)
        } catch {
             print("Failed")
        }
    }
    }
    

    Step:3 - Inside UserCell

    import UIKit
    
    class UserCell: UITableViewCell {
    
    
    @IBOutlet var lblName: UILabel!
    @IBOutlet var lblEmail: UILabel!
    @IBOutlet var lblPost: UILabel!
    @IBOutlet var lblPhone: UILabel!
    @IBOutlet var imageData: UIImageView!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        self.imageData.layer.cornerRadius = self.imageData.frame.height / 2
        self.imageData.layer.borderWidth = 1.0
        self.imageData.layer.borderColor = UIColor.lightGray.cgColor
        self.imageData.layer.masksToBounds = true
    }
    
    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    
        // Configure the view for the selected state
    }
    
    }
    

    Step:4 - Inside AddUserVC

    import UIKit
    import CoreData
    
    class AddUser_VC: UIViewController ,UIImagePickerControllerDelegate ,UINavigationControllerDelegate {
    
    var dictObj: NSManagedObject!
    var isEdit:Bool = false
    
    @IBOutlet var imageData: UIImageView!
    @IBOutlet var txtName: UITextField!
    @IBOutlet var txtEmail: UITextField!
    @IBOutlet var txtPost: UITextField!
    @IBOutlet var txtPhone: UITextField!
    
    @IBOutlet var btnAddUser: UIButton!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
    
        self.imageData.layer.cornerRadius = self.imageData.frame.height / 2
        self.imageData.layer.borderWidth = 1.0
        self.imageData.layer.borderColor = UIColor.lightGray.cgColor
        self.imageData.layer.masksToBounds = true
    
        let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
        self.imageData.isUserInteractionEnabled = true
        self.imageData.addGestureRecognizer(tapGestureRecognizer)
    
        if (self.isEdit == true)
        {
            self.txtName.text = dictObj.value(forKey: "name") as? String ?? ""
            self.txtEmail.text = dictObj.value(forKey: "email") as? String ?? ""
            self.txtPost.text = dictObj.value(forKey: "post") as? String ?? ""
            self.txtPhone.text = String(dictObj.value(forKey: "phone") as? Int ?? 0)
            self.imageData?.image = UIImage(data: dictObj?.value(forKey: "image") as? Data ?? Data())
            self.btnAddUser.setTitle("UPDATE", for: .normal)
        }
    }
    
    
    //MARK: - btnAddUserAction Method -
    @IBAction func btnAddUserAction(_ sender: Any) {
    
        let arrData = [self.txtName,self.txtEmail,self.txtPost,self.txtPhone]
        for txt in arrData
        {
            if (txt?.text == "")
            {
                let alert = UIAlertController(title: "Alert", message: "Please Enter All Fields", preferredStyle: UIAlertController.Style.alert)
                alert.addAction(UIAlertAction(title: "Click", style: UIAlertAction.Style.default, handler: nil))
                self.present(alert, animated: true, completion: nil)
                return
            }
        }
    
        self.createData()
    }
    
    //MARK: - Image Tap Method -
    @objc func imageTapped(tapGestureRecognizer: UITapGestureRecognizer)
    {
        let alert = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
        alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: { _ in
            self.openCamera()
        }))
    
        alert.addAction(UIAlertAction(title: "Gallery", style: .default, handler: { _ in
            self.openGallery()
        }))
    
        alert.addAction(UIAlertAction.init(title: "Cancel", style: .cancel, handler: nil))
    
        self.present(alert, animated: true, completion: nil)
    }
    
    func openCamera()
    {
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.sourceType = UIImagePickerController.SourceType.camera
            imagePicker.allowsEditing = false
            self.present(imagePicker, animated: true, completion: nil)
        }
        else
        {
            let alert  = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    func openGallery()
    {
        if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.photoLibrary){
            let imagePicker = UIImagePickerController()
            imagePicker.delegate = self
            imagePicker.allowsEditing = true
            imagePicker.sourceType = UIImagePickerController.SourceType.photoLibrary
            self.present(imagePicker, animated: true, completion: nil)
        }
        else
        {
            let alert  = UIAlertController(title: "Warning", message: "You don't have permission to access gallery.", preferredStyle: .alert)
            alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    
    func imagePickerController(_ picker: UIImagePickerController,
                               didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
        guard (info[.originalImage] as? UIImage) != nil else {
            fatalError("Expected a dictionary containing an image, but was provided the following: \(info)")
        }
         self.imageData.image = info[.originalImage] as? UIImage
        picker.dismiss(animated: true, completion: nil)
    }
    
    //MARK: - createData
    func createData(){
    
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let userEntity = NSEntityDescription.entity(forEntityName: "UserTable", in: managedContext)!
    
        var user = NSManagedObject()
        if(isEdit == true)
        {
             user = self.dictObj
        }
        else
        {
            user = NSManagedObject(entity: userEntity, insertInto: managedContext)
        }
    
        let image = self.imageData.image!.jpegData(compressionQuality: 0.5)as NSData?
        user.setValue(self.txtName.text, forKeyPath: "name")
        user.setValue(self.txtEmail.text, forKey: "email")
        user.setValue(self.txtPost.text, forKey: "post")
        user.setValue(Int(self.txtPhone.text!), forKey: "phone")
        user.setValue(image, forKey: "image")
    
        do {
            try managedContext.save()
            self.navigationController?.popViewController(animated: true)
    
        } catch let error as NSError {
            print("Could not save. \(error), \(error.userInfo)")
        }
    }
    
    } 
    

    Alternate Methods:

    //MARK: - CoreData Methods -
    func createData(){
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let userEntity = NSEntityDescription.entity(forEntityName: "Movie", in: managedContext)!
        for obj in self.MoviewList.arrMovieData{
            let user = NSManagedObject(entity: userEntity, insertInto: managedContext)
            user.setValue(obj.id, forKey: "id")
            user.setValue(obj.title, forKey: "title")
            user.setValue(obj.overview, forKey: "overview")
            let url = API.IMAGE_BASE_URL + obj.poster_path
            user.setValue(url, forKey: "poster_path")
       }
        do {
            try managedContext.save()
        } catch let error as NSError {
            print("Could not save. \(error), \(error.userInfo)")
        }
    }
    
    
    func retrieveData() {
    
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        let managedContext = appDelegate.persistentContainer.viewContext
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Movie")
        do {
            let result = try managedContext.fetch(fetchRequest)
            var arr = [[String:AnyObject]]()
            for data in result as! [NSManagedObject] {
                var obj = [String:AnyObject]()
                obj["id"] = data.value(forKey: "id") as AnyObject
                obj["title"] = data.value(forKey: "title") as AnyObject
                obj["overview"] = data.value(forKey: "overview") as AnyObject
                obj["poster_path"] = data.value(forKey: "poster_path") as AnyObject
                arr.append(obj)
            }
            self.MoviewList = MovieDataList(data: arr)
            self.tableView.reloadData()
        } catch {
    
            print("Failed")
        }
    }
    
    func deleteAllRecords() {
        let delegate = UIApplication.shared.delegate as! AppDelegate
        let context = delegate.persistentContainer.viewContext
    
        let deleteFetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Movie")
        let deleteRequest = NSBatchDeleteRequest(fetchRequest: deleteFetch)
    
        do {
            try context.execute(deleteRequest)
            try context.save()
            self.createData()
        } catch {
    
        }
    }
    

    0 讨论(0)
  • 2020-11-30 01:39
    #Update Data in #CoreData #iOS #swift 
    
    Simply follow below steps to update data in CoreData which you already saved 
    
    #Step1 :- refer to persistent container & create object of viewContext
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let viewContext = appDelegate.persistentContainer.viewContext
    
    #Step2 :- create FetchRequest
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "User") // here User is entity name 
    
    //Step3 :- add predicate to fetch request by passing attribute and value 
    fetchRequest.predicate = NSPredicate(formate: "userName = %@","XYZ")
    
    //Step4 :- fetch record using viewContext by passing fetchRequest and set new value in it 
    do {
      let results = try viewContext.fetch(fetchRequest) as? [NSManagedObject] 
      if result?.count !=0 {
          result?[0].setValue("ABC",forKey: "userName")
      } 
    } catch {
      print("failed to fetch record from CoreData")
    }
    
    //Step5 :- finally call save method of viewcontext so new value get reflect in CoreData
      do {
        viewContext.save()
    } catch {}
    
    Note :- in predicate the value "XYZ" can be value of attribute and format will contain name of attribute such like username , age password ....etc , in result?[0].setValue you can set new value for particular attribute by passing value and keynote , you can skip step5 and can execute save method inside step4 after Line where we setting new value
    
    0 讨论(0)
提交回复
热议问题