63

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 testStuff() {
    var token = loadLoginData()
    println("Token \(token)")
    saveLoginData("New Token")
    var newToken = loadLoginData()
    println("Token \(newToken)")
}

func saveLoginData(accessToken: String) {
    var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context: NSManagedObjectContext = appDel.managedObjectContext!
    // save data to core data
    var loginData = NSEntityDescription.insertNewObjectForEntityForName("LoginData", inManagedObjectContext: context) as NSManagedObject
    loginData.setValue(accessToken, forKey: "accessToken")
    context.save(nil)
    println("Done saving user")
}

/* Output
Token Optional("12345")
Done saving user
Token Optional("12345")
*/

Load Login Data Func the function that calls on saveLogin data

func loadLoginData() -> String? {
    var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context: NSManagedObjectContext = appDel.managedObjectContext!

    var request = NSFetchRequest(entityName: "LoginData")
    request.returnsObjectsAsFaults = false

    var results: NSArray = context.executeFetchRequest(request, error: nil)!
    if (results.count > 0) {
        var userData: NSManagedObject = results[0] as NSManagedObject
        var accessToken: String = userData.valueForKey("accessToken") as String

        return accessToken.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())

    } else {
        println("0 results returned, potential error")
        return nil
    }
}
humans
  • 549
  • 8
  • 18
slooker
  • 1,060
  • 2
  • 9
  • 16

15 Answers15

63

Since batchupdate is more useful in larger chunks of data, I think this is a more subtle approach.

func saveLoginData(accessToken: String, userName: String) {
    var appDel: AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context: NSManagedObjectContext = appDel.managedObjectContext!

    var fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "LoginData")
    fetchRequest.predicate = NSPredicate(format: "userName = %@", userName)

    if let fetchResults = appDel.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [NSManagedObject] {
        if fetchResults.count != 0{

            var managedObject = fetchResults[0]
            managedObject.setValue(accessToken, forKey: "accessToken")

            context.save(nil)
        }
    }
}

I tried to translate it a bit to your situation if I'm not mistaken, but have not tested it.

fetchRequest.predicate basically sets the filter on the attribute userName from the entity LoginData, with the (user)name you enter when calling the function. Assuming in this example you have only one username with the same name. Then it does a fetchrequest with the given filter, so you can change it's value with setValue with the accesToken you also enter when calling the function. The code after: if fetchResults.count != 0 , only executes when the username exists.

Reinhard Männer
  • 14,022
  • 5
  • 54
  • 116
Henk-Martijn
  • 2,024
  • 21
  • 25
  • You have to put appDel. before managedObjectContext!.executeFetchRequest, so the correct line of code should look like this: if let fetchResults = appDel.managedObjectContext!.executeFetchRequest(fetchRequest, error: nil) as? [NSManagedObject] { – GJ Nilsen Mar 21 '15 at 07:49
  • You can also just use your context that you've already stored in memory, no need to access it again. Just `context.executeFetchRequest(...)`. – Clay Ellis Jun 15 '15 at 23:11
  • I think it will be better to add executeFetchRequest in try block. error not handled here – Vinu David Jose May 07 '16 at 03:04
  • 1
    can you please explaine what means NSPredicate(format: "userName = %@", userName) it's structure of request with param inside sqlite? – jcmaxuser Dec 02 '16 at 11:18
30

Swift 5

You can create a method that can work to both, include and update. Assuming you have an entity created on CoreData with the name Users:

 var context: NSManagedObjectContext {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    return appDelegate.persistentContainer.viewContext
 }
 let user: Users!

 let fetchUser: NSFetchRequest<Users> = Users.fetchRequest()
 fetchUser.predicate = NSPredicate(format: "id = %@", id as String)

 let results = try? context.fetch(fetchUser)

 if results?.count == 0 {
    // here you are inserting
    user = Users(context: context)
 } else {
    // here you are updating
    user = results?.first
 }

 user.id = id
 user.name = name
 ...


try context.save()
ZGski
  • 2,398
  • 1
  • 21
  • 34
Carlos Irano
  • 682
  • 7
  • 8
  • Thanks! You saved me some time! I'm including the tweaks I madeI used in a Swift UI func after data has returned for a web service call. The record_id is the unique field contained on the server so you can just cane this to whatever is your "key" field – Dave Kozikowski Aug 28 '20 at 20:25
  • 4
    Entity names should be singular: `Users` -> `User`. – meaning-matters Dec 24 '20 at 12:36
  • I checked several examples on how to use Core Data in the interwebs, your answer is by far the simplest to understand – André Herculano Nov 03 '22 at 13:31
21

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)")
}
Devbot10
  • 1,193
  • 18
  • 33
10

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]
    // Check notificationId available then not save
    if list!.count == 0 {
        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)")
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Mitul Marsoniya
  • 5,272
  • 4
  • 33
  • 57
4

You're creating multiple new LoginData objects, but your loadLoginData method is always returning the same object, the first one from the fetch request results.

You want to keep updating the same object, so you need to change your saveLoginDetails method.

Instead of creating a new object (which is what insertNewObjectForEntityName) does, use the loadLoginDetails method to get your existing one, and change the property on there.

jrturton
  • 118,105
  • 32
  • 252
  • 268
2
var context: NSManagedObjectContext = appDel.managedObjectContext!
var en = NSEntityDescription.entityForName("ENTITIES_NAME", inManagedObjectContext: context)
let batchUpdateRequest = NSBatchUpdateRequest(entity: en!)
batchUpdateRequest.resultType = NSBatchUpdateRequestResultType.UpdatedObjectIDsResultType
batchUpdateRequest.propertiesToUpdate = ["OBJECT_KEY": "NEWVALUE"]
var batchUpdateRequestError: NSError?
context.executeRequest(batchUpdateRequest, error: &batchUpdateRequestError)
if let error = batchUpdateRequestError {
    println("error")
}

good luck

Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
2

It worked for me you should try this:

let managedContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Students", in: managedContext)
        let request = NSFetchRequest<NSFetchRequestResult>()
        request.entity = entity
        let predicate = NSPredicate(format: "(name = %@)", txtName.text!)
        request.predicate = predicate
        do {
            var results =
                try managedContext.fetch(request)
            let objectUpdate = results[0] as! NSManagedObject
            objectUpdate.setValue(txtName.text!, forKey: "name")
            objectUpdate.setValue(txtPhone.text!, forKey: "phone")
            objectUpdate.setValue(txt_Address.text!, forKey: "address")
            do {
                try managedContext.save()
                txtName.text = ""
                txtPhone.text = ""
                txt_Address.text = ""
                labelStatus.text = "Updated"
            }catch let error as NSError {
              labelStatus.text = error.localizedFailureReason
            }
        }
        catch let error as NSError {
            labelStatus.text = error.localizedFailureReason
        }
Srinivasan_iOS
  • 972
  • 10
  • 12
2

Swift 4,5

Common Function for all Enetities

    func updateEntityObjectByKeyValue<T>(className: T.Type, key: String, value: Any, columns: [String: Any]) -> Bool {
        guard columns.keys.count != 0 else {
            return false
        }
        let context = CoreDataStack.sharedStack.mainContext
        let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: className.self))

       //Depends on data type.Added fetchRequest using Int and string

        if  let sValue = value as? String {
            let predicate = NSPredicate(format: "\(key) == %@", sValue)
            fetchRequest.predicate = predicate
        } else if let iValue = value as? Int {
            let predicate = NSPredicate(format: "\(key) == %d", iValue)
            fetchRequest.predicate = predicate
        }
        
        do {
            let result = try context.fetch(fetchRequest)
            if result.count != 0 {
                if let managedObject = result[0] as? NSManagedObject {
                    for (key, value) in columns {
                        managedObject.setValue(value, forKey: key)
                    }
                    do {
                        CoreDataStack.sharedStack.saveMainContext()
                        return true
                    }
                    catch let error {
                        print(error.localizedDescription)
                    }
                }
            }
            return false
        } catch let error {
            print(error.localizedDescription)
        }
        return false
    }

How to use:

let employeeId = your id
let isSaved = self.updateEntityObjectByKeyValue(className: EmployeeData.self, key: "id", value: employeeId, columns: ["status" :1])
    if isSaved {
       print("Saved")
     }
Priyank Patel
  • 791
  • 8
  • 6
1

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 {

    }
}

enter image description here

Tej Patel
  • 119
  • 2
  • 5
1

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

var isNewRecord = false
let aNewContact: Contact!
let fetchContact: NSFetchRequest<Contact> = Contact.fetchRequest() as! NSFetchRequest<Contact>
fetchContact.predicate = NSPredicate(format: "record_id == %@", contactRemoteModel.contacts[i].record_id as CVarArg)
let results = try? managedObjectContext.fetch(fetchContact)

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")
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Dave Kozikowski
  • 603
  • 6
  • 8
0

It worked for me, you should try this:

guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return}

let managedContext = appDelegate.persistentContainer.viewContext

// if object nil is checked if new entity will be created or created one will be updated

if object == nil {

// create new entity:


let entityObj = NSEntityDescription.entity(forEntityName: "EntityName", in: managedContext)!

let entity = NSManagedObject(entity: entityObj, insertInto: managedContext)


entity("new value", forKeyPath: "entityValue")

do {
    try managedContext.save()
    entities.append(entity)
    self.navigationController?.popViewController(animated: true)

} catch let error as NSError {
    print("Could not save. \(error), \(error.userInfo)")
}
}

else {

// the created entity will be updated selected object is entity -> came from previous view controller:

self.entity?.setValue("updated value", forKey: "entityValue")

do {
    try managedContext.save()

} catch let error as NSError {
    print("Could not save. \(error), \(error.userInfo)")
}

self.navigationController?.popViewController(animated: true)
}
Burcu Kutluay
  • 472
  • 6
  • 14
0

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)")
    }
}
Sumona Salma
  • 127
  • 2
  • 14
0
#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
-1

There's a new feature called Batch Updates.

I think this article will help you:

http://www.bignerdranch.com/blog/new-in-core-data-and-ios-8-batch-updating/

Basicly what you do is use the NSBatchUpdateRequest instead of NSFetchRequest, filter the results with NSPredicate, change the value in the results, and save the data.

Another tutorial in swift:

http://code.tutsplus.com/tutorials/ios-8-core-data-and-batch-updates--cms-22164

Dejan Skledar
  • 11,280
  • 7
  • 44
  • 70
-1

In swift 4 or swift 5, you can used like bellow

func update(accessToken:String,username:String){

    //1
    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else {
            return
    }

    let managedContext =
        appDelegate.persistentContainer.viewContext

    //2
    let fetchRequest =
        NSFetchRequest<NSManagedObject>(entityName: "LoginData")

    // 3
    let predicate = NSPredicate(format: "%K == %@", "username", username)
    fetchRequest.predicate = predicate

    //3

    do {
        let  rs = try managedContext.fetch(fetchRequest)

        for result in rs as [NSManagedObject] {

            // update
            do {
                var managedObject = rs[0]
                managedObject.setValue(accessToken, forKey: "accessToken")

                try managedContext.save()
                print("update successfull")

            } catch let error as NSError {
                print("Could not Update. \(error), \(error.userInfo)")
            }
            //end update

        }

    } catch let error as NSError {
        print("Could not fetch. \(error), \(error.userInfo)")
    }
}
Enamul Haque
  • 4,789
  • 1
  • 37
  • 50
  • 2
    First of all, for future reference, the source of part of this code is [here](https://www.raywenderlich.com/7569-getting-started-with-core-data-tutorial#toc-anchor-004). Second, this code seems not very clean. For example, why do you iterate over the results when you only ever access the first of them? Why do you have nested do statements that aren't required? – Alain Stulz Jan 08 '20 at 17:37