Saving Multiple Data Entries into CoreData - core-data

I'm trying to populate my entity in CoreData for a new app. I made a new function named initializeDB() which sets up new values for the entity and then calls the save() function (within a do try block of course). However it turns out that only the last entity is actually saved. I'm curious as to know why this is the case. I know that only the last one is saved since I do a fetch and only see that the last one is returned.
date = myTimeZoneDateFormatter1.dateFromString("2016-02-03")!
entity.setValue("3.1", forKey: "distanceOfRun")
entity.setValue(date, forKey: "dateOfRun")
do{
try moc.save()
print("save was successful")
}
catch{
print("Entry was not saved") }
date = myTimeZoneDateFormatter1.dateFromString("2016-02-05")!
entity.setValue("3.1", forKey: "distanceOfRun")
entity.setValue(date, forKey: "dateOfRun")
do{
try moc.save()
print("save was successful")
}
catch{
print("Entry was not saved") }
date = myTimeZoneDateFormatter1.dateFromString("2016-02-07")!
entity.setValue("3", forKey: "distanceOfRun")
entity.setValue(date, forKey: "dateOfRun")
do{
try moc.save()
print("save was successful")
}
catch{
print("Entry was not saved") }
Any help in trying to understand this would make me very appreciative.

That's because you are re-saving the same object attributes each time you make save(). You should create a new entity for each object with this method:
let newobject = NSEntityDescription.entityForName("my_entity", inManagedObjectContext: context)
date = myTimeZoneDateFormatter1.dateFromString("2016-02-03")!
newobject.setValue("3.1", forKey: "distanceOfRun")
newobject.setValue(date, forKey: "dateOfRun")
And then save the context again.

Related

How to save a imageview as binary data in Swift 5

I am trying to save the imageview to core data as a binary data. In my function I have already saved a string and it works perfectly. However when I try to do the exact same thing with (theTitle2) it does not work. I also have class cdhandler in my question below which is what is saved in app deleagate.I think what I have to do is somehow convert the image view to a uiimage then save it.
func enterData() {
let appDeldeaget = UIApplication.shared.delegate as! AppDelegate
let context = appDeldeaget.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let theTitle = NSManagedObject(entity: entity!, insertInto: context)
theTitle.setValue(enter.text, forKey: "userName")
let theTitle2 = NSManagedObject(entity: entity!, insertInto: context)
theTitle2.setValue(imageV.image, forKey: "pit")
do {
try context.save()
itemName.append(theTitle)
}
catch { }
//
}
APP DELEGATE
class cdHandler: NSObject {
class func saveObject(userName: String) -> Bool {
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(userName, forKey: "userName")
managedObject.setValue(userName, forKey: "pit")
do {
try context.save()
return true
} catch {
return false
}
}
}
pic of Core Data
If you want to save image in core data, convert image to data then store it. Like
let data = imageV.image?.jpegData(compressionQuality: 1) //image in JPEG format
or
let data = imageV.image?.pngData() // image in PNG format
theTitle2.setValue(data, forKey: "pit")

CoreData context not updating and bool always false?

I am trying to update a user record with a boolean value in coredata. The record itself is updating, but I can only see the change between app sessions, not the same session.
Essentially, I am trying to trap the user agreeing or refusing the apps terms of use. A check is performed on the landing screen after login and if the terms have been agreed to, then continue as normal. However, if the terms have not been agreed to then I need to fire a popover allowing them to accept the terms (This happens every time they hit the landing page until they accept)
I am running the check but no matter what the value is in the core data record, it always evaluates as false:
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
context.automaticallyMergesChangesFromParent = true
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
fetchRequest.predicate = NSPredicate(format: "email == %#", userEmail)
fetchRequest.returnsObjectsAsFaults = false
do {
userRecord = try context.fetch(User.fetchRequest())
if userRecord[0].acceptedTerms != nil && userRecord[0].acceptedTerms {
print("Terms accepted, move along")
} else {
print("Terms refused, pop dialog")
}
} catch {
print("No user found")
}
When a user accepts the terms, I try to update the core data record. Which does update, however I can only see the update between app sessions. Whilst in the same session, if the user hits the landing screen again, the value is still set to false (Or at least the acceptedTerms field in core data is still a 0) - I have done some searching on this and seen there is automaticallyMergesChangesFromParent and also refreshAllObjects() however neither seem to have any effect.
** Update with save code from AppDelegate **
func updateTermsComplete(userLogin: String, termsPermission: String){
let context = self.persistentContainer.viewContext
context.automaticallyMergesChangesFromParent = true
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "User")
fetchRequest.predicate = NSPredicate(format: "email == %#", userLogin)
fetchRequest.returnsObjectsAsFaults = false
do {
userRecord = try context.fetch(fetchRequest) as! [User]
} catch {
print("No user found")
}
if !userRecord.isEmpty {
print("User already exists")
userRecord[0].setValue(termsPermission, forKey: "acceptedTerms")
do {
try context.save()
print("User updated")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
self.saveContext()
}
context.refreshAllObjects()
}
func saveContext () {
let context = persistentContainer.viewContext
context.automaticallyMergesChangesFromParent = true
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}

doubled savings with core data swift 4

developing a little app for my comic collection encountered this issue:
in my second "add comic" VC I have a button and the func below, but I save TWICE entities in manged context (ate least, I think this is the issue)
for example if I have 2 comics yet shown in main VC tableview, go to "add comic VC" and save a third one, going back to main VC I'll print 3 objects with title, number etc but also print 2 new objects with no data as I had saved twice a manger context a "right one" and another one with same number of object but empty. If I keep adding a 4th comic, I'll get 6 complete comic + the 4th and more 6 "blank itmes" with default values "no title"
let kComicEntityName = "Comic"
func addingSingleComic(gotTitle: String, gotIssue: Int16, gotInCollection: Bool ) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: kComicEntityName, in: managedContext)!
let comicToAdd = Comic(entity: entity, insertInto: managedContext)
comicToAdd.comicTitle = gotTitle
comicToAdd.issueNumber = gotIssue
comicToAdd.inCollection = gotInCollection
do {
try managedContext.save()
} catch let error as NSError {
print("could not save. \(error), \(error.userInfo)")
}
print("new single comic crated: title: \(comicToAdd.comicTitle ?? "!! not title !!"), n. \(comicToAdd.issueNumber), owned?: \(comicToAdd.inCollection)")
}
in the main VC I use this to check items in core data
func asyncPrintEntities() {
self.asyncComicEntityArray.removeAll(keepingCapacity: true)
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {return}
let managedContext = appDelegate.persistentContainer.viewContext
let comicFetch : NSFetchRequest<Comic> = Comic.fetchRequest()
asyncFetchRequest = NSAsynchronousFetchRequest<Comic>(fetchRequest: comicFetch) {
[unowned self] (result: NSAsynchronousFetchResult) in
guard let AllComicEntityResult = result.finalResult else {
return
}
self.asyncComicEntityArray = AllComicEntityResult
//************************************
do {
self.asyncComicEntityArray = try managedContext.fetch(comicFetch)
if self.asyncComicEntityArray.count > 0 {
print("Ok! model is not empty!")
} else {
print("No entites availabe")
}
} catch let error as NSError {
print("Fetch error: \(error) description: \(error.userInfo)")
}
guard self.asyncComicEntityArray != nil else {return}
for comicFoundInArray in self.asyncComicEntityArray {
let entity = NSEntityDescription.entity(forEntityName: self.kComicEntityName, in: managedContext)!
var comicTouse = Comic(entity: entity, insertInto: managedContext)
// var comicTouse = Comic() //to be deleted since this kind of init is not allowed, better above insertInto
comicTouse = comicFoundInArray as! Comic
print("comic title: \(comicTouse.comicTitle ?? "error title"), is it in collection? : \(comicTouse.inCollection)")
}
self.MyTableView.reloadData()
//************************************
}
// MARK: - async fetch request 3
do {
try managedContext.execute(asyncFetchRequest)
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
//end of function
}
In your addingSingleComic you create a new Comic here:
let comicToAdd = Comic(entity: entity, insertInto: managedContext)
Then you assign values to the object's properties.
Separately, in asyncPrintEntities, you also create new Comic objects here:
var comicTouse = Comic(entity: entity, insertInto: managedContext)
This time you do not assign values to the object's properties. They will have no title, etc, because you created them but never assigned a title. This line executes once for every object in asyncComicEntityArray, so if the array has two objects, you create two new objects that contain no data. You don't use comicToUse anywhere except in the one print, but it still exists in the managed object context and will still get saved the next time you save changes.
This is why you're getting extra entries-- because you're creating them in this line of code. It's not clear why you're creating them here. You just executed a fetch request, and then you immediately create a bunch of no-data entries which you don't use. It looks like that entire for loop could just be deleted, because the only thing it does is create these extra entries.

How to make instance of entity of core data in Swift?

Entity name :- Article
let entityInstance = Article()
I want to update its attributes, but don't know how to create its instance.
I've used this:
let entityInstance = NSEntityDescription.insertNewObject(forEntityName: "ArticleDetails", into: managedObjectContext) as? ArticleDetails
But it creates new instance instead of updating in the previous one.
To update an entity, you can try the following:
let empId = "001"
let fetchRequest:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "EmpDetails")
let predicate = NSPredicate(format: "empId = '\(empId)'")
fetchRequest.predicate = predicate
do
{
let test = try context?.fetch(fetchRequest)
if test?.count == 1
{
let objectUpdate = test![0] as! NSManagedObject
objectUpdate.setValue("newName", forKey: "name")
objectUpdate.setValue("newDepartment", forKey: "department")
objectUpdate.setValue("001", forKey: "empID")
do{
try context?.save()
}
catch
{
print(error)
}
}
}
catch
{
print(error)
}

How to compute with Core Data

I'm trying to make a small program that keeps count of the amount of times pressed on a button. I'm using Core Data to store the information. The only problem is that I can't figure out how to compute with the information in the core data. If someone can tell me how to make a variable in the code equal to the value of the information in the Core Data I know enough.
If there is another way to compute with the Core Data I would like to know about.
import UIKit
import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
/*let newUser = NSEntityDescription.insertNewObject(forEntityName: "Data", into: context)
newUser.setValue(number, forKey: "number")
do{
try context.save()
print("Saved")
}catch{
print("Error occured in the saving process.")
}*/
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Data")
request.returnsObjectsAsFaults = false
do{
let results = try context.fetch(request)
if results.count > 0{
for result in results as! [NSManagedObject]{
if let number = result.value(forKey: "number") as? Double{
print("number is ", number)
result.setValue(number + 1, forKey: "number")
do{
try context.save()
}catch{
}
}
}
}
}catch{
print("Error with fetching data.")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
var number = 0.0
}
The error it's given on the line with nummer = number += 1:
Cannot assign value of type '()' to type 'Double'
I appreciate all of your answers.
This has nothing to do with Core Data. This line doesn't make sense:
nummer = nummerVar += 1
The += operator increases nummerVar in place. You're assigning this to number, but the return value of the += operation is not a Double, so you can't assign it to a Double.
I'm not completely sure what you intended here. You might have meant
nummer = nummerVar + 1
Or maybe you meant
nummerVar += 1
nummer = nummerVar
Either of those are valid code, but which one you need depends on what you're trying to do.

Resources