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