swift ios how to check fields in core database - ios

how do i check the fields in my core database and also if i wanted to add an entity how would it be possible? below is my code for saving the data , i wanted to add other data aside from name into my core db table using the key groceryitem.
func saveItemInLocalDB(groceryItem : Item) {
let context = getContext()
//retrieve the entity that we just created
let entity = NSEntityDescription.entity(forEntityName: "GroceryItem", in: context)
let item = NSManagedObject(entity: entity!, insertInto: context)
//set the entity values
item.setValue(groceryItem.name, forKey: "name")
item.setValue(false, forKey: "isSelected")
item.setValue(loggedInUserHouseNumber, forKey: "houseNo")
//save the object
do {
try context.save()
print("ang item:", groceryItem.name)
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}

You can try this
let IsFeildAvailable = entity.attributesByName.keys.contains("keyname")
if IsFeildAvailable
{
print("Key/field is exist")
}else{
print("Key/field does not exist")
}

Related

adding data to CoreData takes lot time

// code to add core data. have 2000 contacts to add. but adding 2000 data takes 45 secs.
func addData(contacts: [CNContact]) {
for data in contacts {
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
let newUser = NSManagedObject(entity: entity!, insertInto: context)
newUser.setValue(data.identifier, forKey: "contactIdentifier")
newUser.setValue(data.familyName, forKey: "finalName")
newUser.setValue(data.givenName, forKey: "givenName")
newUser.setValue(data.phoneNumbers.first?.value.value(forKey: "stringValue") as? String ?? "", forKey: "phoneNumber")
do {
try context.save()
} catch {
UIUtility.showErrorAlert("", message: Constants.errorMessage)
}
}
}
First move this line to before the loop since you only need to do it once
let context = appDelegate.persistentContainer.viewContext
Then replace the next two lines with
let newUser = NSEntityDescription.insertNewObject(forEntityName entityName, into: context)
So the start of the function should look like this
let context = appDelegate.persistentContainer.viewContext
for data in contacts {
let newUser = NSEntityDescription.insertNewObject(forEntityName entityName, into: context)
//...
Creating context and entity once (a bit more efficient) and saving the context once (much more efficient) is certainly faster.
func addData(contacts: [CNContact]) {
let context = appDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)!
for data in contacts {
let newUser = NSManagedObject(entity: entity, insertInto: context)
newUser.setValue(data.identifier, forKey: "contactIdentifier")
newUser.setValue(data.familyName, forKey: "finalName")
newUser.setValue(data.givenName, forKey: "givenName")
newUser.setValue(data.phoneNumbers.first?.value.value(forKey: "stringValue") as? String ?? "", forKey: "phoneNumber")
}
do {
try context.save()
} catch {
UIUtility.showErrorAlert("", message: Constants.errorMessage)
}
}

Unable to save values to Core Data

I am trying to store data to Core-Data in AppDelegate itself and then fetch that data from ViewController. For some reason, it is not getting saved in Core-Data. I have tried searching for this issue on the internet but did not get any specific solution. I have pasted the code below -
AppDelegate.swift
func saveContext () {
let context = persistentContainer.viewContext
print(context)
let entity = NSEntityDescription.entity(forEntityName: "Msg", in: context)
print(entity)
let new = NSManagedObject(entity: entity!, insertInto: context)
print(new)
print(getData.alert_message)
new.setValue(getData.alert_message, forKey: "title")
do {
try context.save()
print("save")
print(new.value(forKey: "title"))
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
Console Output
You can fetch record from the entity by NSFetchRequest
Try with below method, You just need to pass name of the entity as argument of the function.
func getAllRecordFromTableWhere(_ tableName: String) -> [NSManagedObject]? {
let fetchRequest = NSFetchRequest<NSManagedObject>(entityName: tableName)
do {
return try managedContext.fetch(fetchRequest)
} catch let error as NSError {
print("Could not fetch. \(error), \(error.userInfo)")
}
return nil
}
and call function like
if let arrayOfData = DBHelper.getAllRecordFromTableWhere("Msg") {
print(arrayOfData)
}
Hear I have Set My Own Solution, Hope This help You
let contex = ((UIApplication.shared.delegate) as! AppDelegate).persistentContainer.viewContext
func SaveData()
{
let entity = NSEntityDescription.insertNewObject(forEntityName: "Employee", into: contex);
entity.setValue(txtname.text, forKey: "empname") // txtname.text is My TexField name
entity.setValue(txtadd.text, forKey: "empadd");
do
{
try contex.save();
}
catch
{
}
}
I think you are not giving values to all attributes of the entity so check that first.
try something like
new.setValue(msgdata, forKey: "msgdata")
//msgdata is what you want to save on Coredata entity
//try something like this
In my case i was trying to update data saved in core data. but every time it was returning the old data ( not the updated version )
Saved successfully message was being printed in console same as yours
Here are some simple steps that finally solved my problem
fetch data with a NSFetchRequest
save data into a temp variable
delete old data from core data
modify data from temp variable
and finally save context
Here is my update data function
func updateUserData(_ userDetails: UserModel) {
let request = UserDetails.fetchRequest() as NSFetchRequest<UserDetails>
do {
let result = try persistentContainer.viewContext.fetch(request)
if let data = result.first?.userData as Data? {
var loginModel = LoginModel(data: data)
loginModel?.user = userDetails
self.clearUserData() //deleting old data
self.userLoginData = loginModel?.jsonData
}
}catch let error as NSError {
debugPrint(error.localizedDescription)
}
}

How to re-use a bunch of code when 2 objects are involved in Swift

I have faced this issue many times, but finally asking how to solve this in Swift and iOS. I have the same code block that runs against 2 different kind of objects, but I can't figure out, how to apply the code to either of the 2 object types with it being strongly typed. In other languages (like PHP) I would just put a generic var myVar = nil at the top of block and then set that to one or the other of those objects, then hang the code off of it, but swift won't let me do that.
How do you handle this programming situation in Swift/iOS?
static func entitySetup(jsonObject: JSON, object: MyCoreDataEntityObject?) {
if let existingObj = object { // existingObj = a MyCoreDataEntityObject
existingObj.setValue(jsonObject["firstName"].stringValue, forKey: "firstName")
existingObj.setValue(jsonObject["lastName"].stringValue, forKey: "lastName")
existingObj.setValue(jsonObject["address"].stringValue, forKey: "address")
existingObj.setValue(jsonObject["phone"].stringValue, forKey: "phone")
} else { // newObj = NSManagedObject
let entity = NSEntityDescription.entity(forEntityName: "MyCoreDataEntityObject", in: self.context)
let newObj = NSManagedObject(entity: entity!, insertInto: self.context)
newObj.setValue(jsonObject["firstName"].stringValue, forKey: "firstName")
newObj.setValue(jsonObject["lastName"].stringValue, forKey: "lastName")
newObj.setValue(jsonObject["address"].stringValue, forKey: "address")
newObj.setValue(jsonObject["phone"].stringValue, forKey: "phone")
}
do {
try self.context.save()
} catch let error as NSError {
print("ERROR: Could not save \(error), \(error.userInfo)")
completionHandler(false)
}
}
Since both objects are NSManagedObject, you can do this:
let mangedObject: NSManagedObject
if let existingObj = object {
managedObject = existingObj
} else {
let entity = NSEntityDescription.entity(forEntityName: "MyCoreDataEntityObject", in: self.context)
managedObject = NSManagedObject(entity: entity!, insertInto: self.context)
}
managedObject.setValue(jsonObject["firstName"].stringValue, forKey: "firstName")
managedObject.setValue(jsonObject["lastName"].stringValue, forKey: "lastName")
managedObject.setValue(jsonObject["address"].stringValue, forKey: "address")
managedObject.setValue(jsonObject["phone"].stringValue, forKey: "phone")
do {
try self.context.save()
} catch let error as NSError {
print("ERROR: Could not save \(error), \(error.userInfo)")
completionHandler(false)
}
And as suggested, the four lines calling setValue can be simplified as:
for key in ["firstName", "lastName", "address", "phone"] {
managedObject.setValue(jsonObject[key].stringValue, forKey: key)
}
Try this
static func entitySetup(jsonObject: JSON, object: MyCoreDataEntityObject?) {
let newObject = object ?? NSManagedObject(entity: NSEntityDescription.entity(forEntityName: "MyCoreDataEntityObject", in: self.context)!, insertInto: self.context)
for key in ["firstName", "lastName", "address", "phone"] {
newObject.setValue(jsonObject[key].stringValue, forKey: key)
}
do {
try self.context.save()
} catch let error as NSError {
print("ERROR: Could not save \(error), \(error.userInfo)")
completionHandler(false)
}
}

Swift 3 / iOS 10, Proper Core Data Usage

Before upgrading my apps to Swift 3 and iOS 10, I had no problems with using CoreData as a data store for simple objects. Lightweight Migrations were simple, saving and fetching was simple, ect. But ever since the recent upgrade, I have had nothing but trouble with CoreData.
My question is in two parts. First, does anyone know of any good resources to help me learn how CoreData works behind the scenes so I can get better at debugging it? Apple's docs are extremely limiting, and all the articles I read act like the new CoreData is so simple. I have decent experience with relational databases, so CoreData is adding an uncomfortable layer of abstraction for me.
Second, what is wrong with the following code? Lightweight migrations aren't working as they did before iOS 10, using this code. Objects are saving to CoreData (I can interact with them in app after saving), but then disappear after the app is restarted.
lazy var persistentContainer: NSPersistentContainer = {
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
let container = NSPersistentContainer(name: "MY_APP")
container.persistentStoreDescriptions = [description]
let description = NSPersistentStoreDescription()
description.shouldInferMappingModelAutomatically = true
description.shouldMigrateStoreAutomatically = true
container.persistentStoreDescriptions = [description]
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
I'm using a separate file to abstract the storing of my objects:
class Repository
{
func getContext () -> NSManagedObjectContext
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
func delete<T>(_ a: some T)
{
getContext().delete(a as! NSManagedObject)
}
// ----------- Password Repo ----------
func savePassword(name: String, hint: String, un: String) {
let context = getContext()
//retrieve the entity that we just created
let entity = NSEntityDescription.entity(forEntityName: "Password", in: context)
let transc = NSManagedObject(entity: entity!, insertInto: context)
//set the entity values
transc.setValue(name, forKey: "name")
transc.setValue(hint, forKey: "thing")
transc.setValue(un, forKey: "newThing")
//save the object
do {
try context.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
func updatePassword(pas: Password) -> Password
{
let context = getContext()
// sec.is_new = false
// TODO, add updates
// Try updating the model in the DB
do {
try context.save()
} catch {
print(error)
}
return pas
}
func fetchPasswords() -> [Password]
{
let context = getContext()
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<Password> = Password.fetchRequest() as! NSFetchRequest<Password>
let sortDescriptor = NSSortDescriptor(key: "name", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
do {
//go get the results
let searchResults = try getContext().fetch(fetchRequest)
return searchResults
} catch {
print("Error with request: \(error)")
}
return []
}
// ----------- End Password Repo ----------
// ----------- Hints Repo ----------
func saveHint (name: String, hint: String) {
let context = getContext()
//retrieve the entity that we just created
let entity = NSEntityDescription.entity(forEntityName: "Hint", in: context)
let transc = NSManagedObject(entity: entity!, insertInto: context)
//set the entity values
transc.setValue(value1, forKey: "some_string")
transc.setValue(value2, forKey: "some_thing")
//save the object
do {
try context.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
func fetchHints() -> [Hint]
{
let context = getContext()
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<Hint> = Hint.fetchRequest() as! NSFetchRequest<Hint>
let sortDescriptor = NSSortDescriptor(key: "my_key", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
do {
//go get the results
let searchResults = try getContext().fetch(fetchRequest)
return searchResults
} catch {
print("Error with request: \(error)")
}
return []
}
}
Then I call this Repository class like so:
Repository().savePassword(name: nameText.text!, hint: hintSoFarLabel.text!, un: "Hey")
The Repository class is working, until I restart the app...
I'm also trying to migrate to a new version of my Core Data Model which simply adds a non-optional String attribute (with default value), which would be a simple lightweight migration in iOS 9/Swift 2. What am I missing about swift 3 lightweight migrations?
I have no doubt that the problem is me not understanding CoreData in iOS 10 well enough. I've been a software engineer for a while, but I've only been working with iOS and Swift for a few months, so please be gentle. And thank's in advance!
Well, I feel like an idiot. I added a non-optional string and didn't give it a default value. I always gave default values to non-string types, but the way Xcode is set up made it appear that it would just give strings a default value of "" if no other was given.
Adding a default value to the new attribute allowed the migration to work in Swift3/iOS10. Noob mistake, but maybe it will help someone here in the future.

Saving object to core data with NSPredicate

I'm trying to save an object to Core Data which is fetched from Parse, but i'd like only those which doesn't contain a name which is already in database:
func fetchFromParse() {
let entity = NSEntityDescription.entityForName("Medicine", inManagedObjectContext: context)
let query = PFQuery(className: "Medicine")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
for object in objects! {
let medicine = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: self.context)
if let name = object["medicineName"] as? String,
amount = object["amountQuantity"] as? String {
let predicate = NSPredicate(format: "name != %#", name)
self.fetchRequest.predicate = predicate
do{
let fetchedEntities = try self.context.executeFetchRequest(self.fetchRequest) as! [Medicine]
//save to Core Data
medicine.setValue(name, forKey: "name")
medicine.setValue(amount, forKey: "amount")
} catch let error as NSError{
print(error)
}
do {
try self.context.save()
self.tableView.reloadData()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
}
}
}
}
Fetch data from Core Data
func fetchFromCoreData() {
do {
let results = try context.executeFetchRequest(fetchRequest)
medicines = results as! [Medicine]
} catch let error as NSError {
print("Could not fetch \(error), \(error.userInfo)")
}
}
i put the in viewWillAppear:
if Reachability.isConnectedToNetwork() {
//fetching data from Parse
fetchFromParse()
fetchFromCoreData()
tableView.reloadData()
} else {
//fetching data from Core data
fetchFromCoreData()
logOutButton.enabled = false
}
But it doesn't work. Any suggestions how to repair it ?
You kind of have everything, just not hooked up. You shouldn't be instantiating and inserting the new object until after you've executed and checked the fetch. You currently execute the fetch but don't check to see if there is a duplicate. Both of these issues need to be resolved, something along the lines of:
let entity = NSEntityDescription.entityForName("Medicine", inManagedObjectContext: context)
let query = PFQuery(className: "Medicine")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if error == nil {
for object in objects! {
if let name = object["medicineName"] as? String,
amount = object["amountQuantity"] as? String {
let predicate = NSPredicate(format: "name = %#", name)
self.fetchRequest.predicate = predicate
do{
let fetchedEntities = try self.context.executeFetchRequest(self.fetchRequest) as! [Medicine]
//save to Core Data
if fetchedEntities.count <= 0 {
let medicine = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: self.context)
medicine.setValue(name, forKey: "name")
medicine.setValue(amount, forKey: "amount")
}
} catch let error as NSError{
print(error)
}
}
}
do {
try self.context.save()
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
}
}
}

Resources