I am following raywenderlich's tutorial for Core Data : Tutorial
the issue I am facing is that in this snippet of code :
let entity = NSEntityDescription.entity(forEntityName: "Person", in: managedContext)!
let person = NSManagedObject(entity: entity,insertInto: managedContext)
The entity value is returned nil and app gets crashed . Is there something that I missed because I have tried 3-4 times but still the same issue
If you say what you say is correct (crashing on the mentioned line) then the Person entity does not exist in the data model.
Please verify that the person exists in the model:
Also following the linked tutorial I suspect you're calling the save method, like so:
func save(name: String) {
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
// 1
let managedContext =
appDelegate.persistentContainer.viewContext
// 2
let entity =
NSEntityDescription.entity(forEntityName: "Person",
in: managedContext)!
let person = NSManagedObject(entity: entity,
insertInto: managedContext)
// 3
person.setValue(name, forKeyPath: "name")
// 4
do {
try managedContext.save()
people.append(person)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
Which suggests that you'll also have to check for the name attribute on the Person entity:
I hope this helps you.
Related
I've implemented core data in my application successfully. Everything was working fine but I got an issue. I'm using merge policy to update records.
I've two Entities name Issues and Members with relation one to many. One issue has many members.
Data comes from the server and saved in these two Entities:
Object A
Object B
Object C
This data comes first time and save in coredata. Data updates on server and when fetching second time , this data comes:
Object A
Object B
It should update and remove the Object C, but Object C still in coredata.
Please help me what i'm doing wrong here. Thanks in advance.
This is my code:
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
class func saveIssues(with json: JSON)
{
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "Issues", in: context)
let issue = NSManagedObject(entity: entity!, insertInto: context) as! Issues
issue.setValue(json["Id"].stringValue, forKey: "id")
issue.setValue(json["Name"].stringValue, forKey: "name")
issue.setValue(json["CreatedByName"].stringValue, forKey:"createdByName")
for issueMembers in json["Members"].arrayValue
{
let members = NSEntityDescription.insertNewObject(forEntityName: "Members", into: context) as! Members
members.setValue(issueMembers["FullName"].stringValue, forKey: "fullName")
members.setValue(issueMembers["PictureUrl"].stringValue, forKey: "picture_Url")
members.setValue(issueMembers["LoginId"]. stringValue, forKey: "loginId")
issue.addToIssueMembers(members)
}
context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
do{
try context.save()
}catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
I investigated it a little bit and found that no one merge policy suites your needs: in case of uniqueness constraints, both NSRollbackMergePolicy and NSOverwriteMergePolicy save only old (existed on persistent store) set of objects in relationship, and both NSMergeByPropertyStoreTrumpMergePolicy and NSMergeByPropertyObjectTrumpMergePolicy save all objects in relationship the object had in two versions (on disk and in memory). So seems like you have to manage the relationship yourself...
I have an app that has some form fields. When the form is submitted it writes the data to my Core Data Object. However, when the form is submitted again it overwrites the existing data instead of appending to it, which is what I want to happen instead.
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let userEntity = NSEntityDescription.entity(forEntityName: "User", in: managedContext)
let newUser = NSManagedObject(entity: userEntity! , insertInto: managedContext)
newUser.setValue(titleField, forKey: "title")
newUser.setValue(firstNameField, forKey: "firstName")
newUser.setValue(lastNameField, forKey: "lastName")
newUser.setValue(emailField, forKey: "email")
newUser.setValue(affiliatedOrgField, forKey: "affiliatedOrg")
newUser.setValue(ukRegionField, forKey: "ukRegion")
newUser.setValue(privacyChecked, forKey: "privacyPolicy")
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
I have tried using
let userEntity = NSEntityDescription.insertNewObject(forEntityName: "User", into: managedContext)
let newUser = NSManagedObject(entity: userEntity, insertInto: managedContext)
but I get the following error on my 'newUser' constant
Cannot convert value of type 'NSManagedObject' to expected argument type 'NSEntityDescription'
Can anybody help please?
Since you are using NSPersistentContainer you are using at least macOS 10.12 or iOS 10.10. Apple has added some very nice simplifications to Core Data so that it is unnecessary, for example, to use string-based keys which have the disadvantage to being resistant to compiler checking.
The “new Core Data pattern” looks like this:
let managedContext = appDelegate.persistentContainer.viewContext
let newUser = User(context: managedContext)
newUser.title = ...
newUser.firstName = ...
It could be as simple as that. Let me know if it works for you.
You need to keep a reference to your newly created user and then update that user. So do as Tom E suggested
let newUser = User(context: managedContext)
newUser.title = ...
newUser. firstName = ...
Then let newUser be a property in your class of type User or part of an array, [User], depending on your use case
var newUser: User?
When the form gets updated then instead of creating a new user, update the changed properties like
newUser.email = emailField
and call save to persist the update
try managedContext.save()
Cast the object to User:
let newUser = NSEntityDescription.insertNewObject(forEntityName: "User", into: managedContext) as! User
...<fill the fields>
simple way:
let newUser = User(entity: User.entity(), insertInto: managedContext)
This question already has answers here:
How do you update a CoreData entry that has already been saved in Swift?
(15 answers)
Closed 5 years ago.
In my entity i have 5 attributes and some values are already saved, i cannot search specific value from saved data and update the data and save it.
Data 1
name = Conc;
url = "http://192.168.1.12/snapshot";
ipaddress = "http://192.168.1.102";
pass = we;
prof = "Profile_1";
user = web;
Data 2
name = P1;
url = "http://192.168.1.150/hello";
ipaddress = "http://192.168.1.112";
pass = hello;
prof = "Profile_1";
user = web;
All this is saved in my core data i wanted to search the name P1 and replace the data which user adds into the text field and update it.
but it adds as a new entry into the core data.
code used to save the data:
var coreDataIpAddress: [NSManagedObject] = []
guard let appDelegate =
UIApplication.shared.delegate as? AppDelegate else {
return
}
// 1
let managedContext =
appDelegate.persistentContainer.viewContext
// 2
let entity =
NSEntityDescription.entity(forEntityName: "Data",
in: managedContext)!
let Data = NSManagedObject(entity: entity,
insertInto: managedContext)
// 3
cameraData.setValue(ipAddress, forKey: "ipaddress")
cameraData.setValue(snapshotUrl, forKey: "url")
cameraData.setValue(cameraName, forKey: "name")
cameraData.setValue(userName, forKey: "user")
cameraData.setValue(password, forKey: "pass")
cameraData.setValue(profileToken, forKey: "prof")
// 4
do {
try managedContext.save()
saveCameraDetails.append(Data)
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
Every time this line of code executes:
let Data = NSManagedObject(entity: entity,
insertInto: managedContext)
...you are telling Core Data to create a new instance. That's why you get new entries, because you keep creating them. If you want to update an existing instance, you need to get the existing instance instead of creating a new one. Usually you do this with an NSFetchRequest. Apple provides detailed documentation with sample code that explains this.
I did go through other posts that dealt this issue. But I couldn't find much with regard to my problem. Hope somebody can help. My issue is...I am having a certain edited record that I want to display in my tableview. For that I want to update that entry in Core-Data also. I am not able to figure out how that can be done.
This is how I am bringing the edited data in tableview and saving in Core Data. The updation has to be done somewhere in between but I am not able to figure out exactly how and where..?
#IBAction func saveToMainEditViewController (segue:UIStoryboardSegue) {
let detailViewController = segue.source as! EditCategoriesTableViewController
let index = detailViewController.index
let modelString = detailViewController.editedModel //Edited model has the edited string
let myCategory1 = Category(context: self.context)
myCategory1.categoryName = modelString
mangObjArr[index!] = myCategory1
//Saving to CoreData
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedContext = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Category", in: managedContext)
let category = NSManagedObject(entity: entity!, insertInto: managedContext)
category.setValue(myCategory1.categoryName, forKeyPath: "categoryName")
category.setValue(myCategory1.categoryId, forKey: "categoryId")
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
Steps:
Understand basic concepts
Fetch Record
Update Record
Save context
Concepts:
This is just a crude explanation, the proper explanation is in the link below.
Though it is time consuming, please refer to the link below, it will help you understand CoreData. If you don't understand you will encounter a lot of problems later on.
Entity:
In the core data model you can create entities, these are the tables.
Managed Object:
This is the class representation of the entity
Each instance of this class would represent a single row in the table.
Managed Object Context:
Imagine managed object context like a piece of paper / scratch pad
The managed objects are created / updated / deleted on a specific managed object context.
You can save / discard the changes made to a managed object context.
Not Thread Safe:
When ever you perform anything on a managed object context, make sure you use within context.performAndWait { }. This will ensure that context operations are performed on the context's queue (thread).
Fetch and Update:
func fetch() {
let request : NSFetchRequest< Category> = Category.fetchRequest()
//Predicate builds the where clause to filter records
//This is a sample, so edit based on your requirement
request.predicate = NSPredicate(format: "categoryID = %#", argumentArray: [10])
context.performAndWait {
do {
let categories = try context.fetch(request)
//Update
for category in categories {
category.name = "aaa"
}
}
catch {
print("error = \(error)")
}
}
}
Save:
func save() {
if context.hasChanges {
context.performAndWait {
do {
context.save()
}
catch {
print("Save error: \(error)")
}
}
}
}
Reference:
https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/index.html
I have a Job Model in CoreData and within this object I have values like job_id and start_date and a one-to-many relation to JobImage which is also a CoreData Model.
If I create a new Job object and save it together with some Images, everything works well. This looks like that:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let entity = NSEntityDescription.entityForName("Job", inManagedObjectContext: managedContext)
job = Job(entity: entity!, insertIntoManagedObjectContext: managedContext)
job?.setValue(NSDate(), forKey: "start_date")
job?.setValue(true, forKey: "running")
if let id = jobJson.id {
job?.setValue(id, forKey: "job_id")
}
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
print("Something unexpected happened...")
}
and adding images like that:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let jpegImage = UIImageJPEGRepresentation(image, 1.0)
let entity = NSEntityDescription.entityForName("JobImage", inManagedObjectContext: managedContext)
let imageObject = JobImage(entity: entity!, insertIntoManagedObjectContext: managedContext)
imageObject.data = jpegImage
imageObject.job = job
do {
try managedContext.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
print("Something unexpected happened...")
}
where job is the Job object which I created earlier (I saved it in the global variable like that job = Job(entity: entity!, insertIntoManagedObjectContext: managedContext)) and image is just a UIImage.
The JobImage object has a data property which is "Binary Data".
I set the job property which is the relation to my Job object to job and save the result.
Everything I mentioned until now works great but if I don't create a new entity but I fetch an existing one and try to add a relation to a new JobImage and save the result, it fails. Fetching the object works great, I can access all the properties stored within the Job object but saving another image to the images relation fails.
I fetch the Job object like that:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "Job")
fetchRequest.predicate = NSPredicate(format: "running == true")
do {
let results = try managedContext.executeFetchRequest(fetchRequest)
let jobs = results as! [Job]
if jobs.count > 0 {
job = jobs[0]
}
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
} catch {
print("Something unexpected happened...")
}
Again, I store the Job object in my global property job and use it to create new relations to images and save them as before but this time it fails with the following error:
Could not save Error Domain=NSCocoaErrorDomain Code=1550 "The operation couldn’t be completed. (Cocoa error 1550.)" UserInfo={NSValidationErrorObject= (entity: Job; id: 0xd000000000040000
...
NSValidationErrorValue: Relationship 'job_images' on managed object (0x7fb094029f10) (entity: Job; id: 0xd000000000040000
...
NSValidationErrorKey: job_images, NSLocalizedDescription: The operation couldn’t be completed. (Cocoa error 1550.)]
Where job_images is my relation from Job to JobImage.
I read through some StackOverflow questions with Cocoa error 1550 but none of the answers seem to work for my problem. Do you have any ideas?