I created an extension for my Core Data subclass, here I implemented a method to pre populate the table, first I check if here is anything in the table, and I insert some values, but I get an error when I do a fetch:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'executeFetchRequest:error: <null> is not a valid NSFetchRequest.'
import Foundation
import CoreData
extension SimulationParams {
public static func feedSimulationParams(context: NSManagedObjectContext) {
let fetchRequest : NSFetchRequest<NSFetchRequestResult>
if #available(iOS 10.0, *) {
fetchRequest = SimulationParams.fetchRequest()
} else {
fetchRequest = NSFetchRequest(entityName: "SimulationParams")
}
let idDescriptor: NSSortDescriptor = NSSortDescriptor(key: "id", ascending: false)
fetchRequest.sortDescriptors = [idDescriptor]
fetchRequest.fetchLimit = 1
var newId = 0;
do {
let results = try context.fetch(fetchRequest)
if(results.count == 0){
self.setValue(getId(fetchRequest: fetchRequest, context: context), forKeyPath: "id")
self.setValue(1.5, forKeyPath: "bankFeePercentage")
self.setValue(1, forKeyPath: "consoMaxMonthly")
self.setValue(12, forKeyPath: "consoMinMonthly")
self.setValue(3.5, forKeyPath: "consoRatePercentage")
self.setValue(4, forKeyPath: "fileFeePercentage")
self.setValue(1, forKeyPath: "immoMaxMonthly")
self.setValue(25, forKeyPath: "immoMinMonthly")
self.setValue(2.05, forKeyPath: "immoRatePercentage")
self.setValue(3, forKeyPath: "prepaymentPenaltyPercentage")
self.setValue(1, forKeyPath: "notaryGridId")
do {
try context.save()
} catch let error as NSError {
print ("Error first demande insertion \(error)")
}
}
} catch {
let fetchError = error as NSError
print(fetchError)
}
}
}
Solution:
Warning, you have to delete the module in the Data Model Inspector and set it to global namespace.
You have to do this on your code:
let fetchRequest : NSFetchRequest<NSFetchRequestResult>
if #available(iOS 10.0, *) {
fetchRequest = Params.fetchRequest()
} else {
fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Params")
}
//let predicate = NSPredicate(format: "key=%#", key)
//fetchRequest.predicate = predicate
do {
let results = try context.fetch(fetchRequest)
if(results.count != 0){
let params = NSEntityDescription.insertNewObject(forEntityName: "Params", into: context) as! Params
params.setValue(value, forKey: "value")
do {
try context.save()
} catch let error as NSError {
print ("Error first demande insertion \(error)")
}
} else if (results.count == 0) {
let params = NSEntityDescription.insertNewObject(forEntityName: "Params", into: context) as! Params
params.key = key
params.value = value
context.insert(params)
}
} catch {
let fetchError = error as NSError
print(fetchError)
}
Related
I was wondering is there a way to update a table view with an animation, when a NSBatchRequest is executed? This code does the job, but there is no animation it just removes everything really quick.
#objc func resetButtonPressed() {
let deleteRequest = NSBatchDeleteRequest(fetchRequest: Company.fetchRequest())
let context = CoreDataManager.shared.persistentContainer.viewContext
do {
try context.execute(deleteRequest)
try context.save()
try companyController.performFetch()
tableView.reloadData()
} catch let err {
print("Unable to perform company batch delete request", err)
}
}
I am trying to get a similar animation when you use an array. The code looks something like this.
#objc func resetButtonPressed() {
// This Basically does the batch delete request
CoreDataManager.shared.deleteAllCompanies()
var indexsToRemove = [IndexPath]()
for (index, _) in companies.enumerated() {
let indexPath = IndexPath(row: index, section: 0)
indexsToRemove.append(indexPath)
}
companies.removeAll()
tableView.deleteRows(at: indexsToRemove, with: .left)
}
I tried doing this but no luck. My app just keep crashing.
#objc func resetButtonPressed() {
let deleteRequest = NSBatchDeleteRequest(fetchRequest: Company.fetchRequest())
let context = CoreDataManager.shared.persistentContainer.viewContext
do {
var indexsToRemove = [IndexPath]()
for (_,company) in companyController.fetchedObjects!.enumerated() {
guard let indexPath = companyController.indexPath(forObject: company) else { return }
indexsToRemove.append(indexPath)
}
try context.execute(deleteRequest)
try context.save()
//Doesn't allow me to use this because its only a get
companyController.fetchedObjects?.removeAll()
//This keeps crashing my app.
tableView.deleteRows(at: indexsToRemove, with: .fade)
} catch let err {
print("Unable to perform company batch delete request", err)
}
}
Also my companyController have multiple sections. It look something like this.
lazy var companyController: NSFetchedResultsController<Company> = {
let context = CoreDataManager.shared.persistentContainer.viewContext
let request: NSFetchRequest<Company> = Company.fetchRequest()
let nameSort = NSSortDescriptor(key: "name", ascending: true)
let dateSort = NSSortDescriptor(key: "date", ascending: true)
request.sortDescriptors = [nameSort,dateSort]
//Company has a type property ex: Electronics, Gas, Groceries ...
let controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: "type", cacheName: nil)
controller.delegate = self
do {
try controller.performFetch()
} catch let err {
print("Unable to fetch company in controller", err)
}
return controller
}()
I am working on an app that uses CoreData.
I am strong numbers and retrieving them, but when i store more than one field it only shows the last field with the number but a 0 in all the others. below is my codes.
to store them...
let CWConvert = Double(CWeight.text!)
storeTranscription18CW(pageText: (CWConvert)!, textFileUrlString: "cWeight")
savePlus += 1
let TWConvert = Double(TWeight.text!)
storeTranscription18TW(pageText: (TWConvert)!, textFileUrlString: "tWeight")
and...
func getContext () -> NSManagedObjectContext {
_ = UIApplication.shared.delegate as! AppDelegate
return DataController().managedObjectContext
}
func storeTranscription18CW (pageText: Double, textFileUrlString: String) {
let context = getContext()
//retrieve the entity that we just created
let entity = NSEntityDescription.entity(forEntityName: "TextInputs", in: context)
let transc = NSManagedObject(entity: entity!, insertInto: context)
// set the entity values
transc.setValue(pageText, forKey: "cWeight")
//save the object
do {
try context.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
func storeTranscription18TW (pageText: Double, textFileUrlString: String) {
let contexta = getContext()
//retrieve the entity that we just created
let entitya = NSEntityDescription.entity(forEntityName: "TextInputs", in: contexta)
let transc = NSManagedObject(entity: entitya!, insertInto: contexta)
// set the entity values
transc.setValue(pageText, forKey: "tWeight")
//save the object
do {
try contexta.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
and to retrive.
func getTranscriptions18CW () {
//create a fetch request, telling it about the entity
let fetchRequesta: NSFetchRequest<TextInputs> = TextInputs.fetchRequest()
do {
//go get the results
let searchResults18CW = try getContext().fetch(fetchRequesta)
for transa in searchResults18CW as [NSManagedObject] {
if let resulta = transa.value(forKey: "cWeight") {
if let stra = resulta as? String {
CWeight.text = stra
}else {
CWeight?.text = "\(resulta)"
}
}
}
//get the Key Value pairs (although there may be a better
}catch {
print("Error with request: \(error)")
}
}
func getTranscriptions18TW () {
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<TextInputs> = TextInputs.fetchRequest()
do {
//go get the results
let searchResults18TW = try getContext().fetch(fetchRequest)
for trans in searchResults18TW as [NSManagedObject] {
if let result = trans.value(forKey: "tWeight") {
if let str = result as? String {
TWeight.text = str
}else {
TWeight?.text = "\(result)"
}
}
//get the Key Value pairs (although there may be a better way to do that...
}
}catch {
print("Error with request: \(error)")
}
}
i have tried different names but get the same it only shows the last one as the real number if i moment out the last one then the first shows the real value.
Try something more like this to save so that you are saving both in the same row.
func storeTranscription18TW () {
let contexta = getContext()
//retrieve the entity that we just created
let entitya = NSEntityDescription.entity(forEntityName: "TextInputs", in: contexta)
let transc = NSManagedObject(entity: entitya!, insertInto: contexta)
// set the entity values
transc.setValue(CWConvert, forKey: "cWeight") // Note the change from pageText
transc.setValue(TWConvert, forKey: "tWeight") // Note the change from pageText
//save the object
do {
try contexta.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
Then when you do a get they would both be done in the same function as well.
I created a table: key, value.
It's just for save some params, when the key doesn't exist, I do an insert but when it exist I update the value.
In my case, when the key already exist it does an another insert in ma table with key equal to nil:
public static func insertValueWithKey(context: NSManagedObjectContext, key:String, value:String){
let fetchRequest : NSFetchRequest<NSFetchRequestResult>
if #available(iOS 10.0, *) {
fetchRequest = Params.fetchRequest()
} else {
fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Params")
}
let predicate = NSPredicate(format: "key=%#", key)
fetchRequest.predicate = predicate
do {
let results = try context.fetch(fetchRequest)
if(results.count != 0){
let paramsDescription = NSEntityDescription.entity(forEntityName: "Params", in: context)
let params = NSManagedObject(entity: paramsDescription!, insertInto: context) as! Params
params.value = value
do {
try context.save()
} catch let error as NSError {
print ("Error first demande insertion \(error)")
}
} else if (results.count == 0) {
let params = NSEntityDescription.insertNewObject(forEntityName: "Params", into: context) as! Params
params.key = key
params.value = value
context.insert(params)
do {
try context.save()
} catch let error as NSError {
print ("Error first demande insertion \(error)")
}
}
} catch {
let fetchError = error as NSError
print(fetchError)
}
}
I don't understand why because it work as well on simulator but not on device...
replace:
let params = NSManagedObject(entity: paramsDescription!, insertInto: context) as! Params
with
let params = results.last as! Params
NSManagedObject(entity: insertInto:) is functionally the same as NSEntityDescription.insertNewObject(forEntityName:into:)
So I have this code which works fine, but I want a much better one.
func deleteCoreDataObjects() {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
//where groupData is an Array of an Entity
for i in 0..<self.groupData.count {
context.delete(groupData[i])
}
(UIApplication.shared.delegate as! AppDelegate).saveContext()
}
Currently I'm deleting the objects one by one via for loop.
You can try this:
func deleteAllData(entity: String)
{
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let managedContext = appDelegate.managedObjectContext
let fetchRequest = NSFetchRequest(entityName: entity)
fetchRequest.returnsObjectsAsFaults = false
do
{
let results = try managedContext.executeFetchRequest(fetchRequest)
for managedObject in results
{
let managedObjectData:NSManagedObject = managedObject as! NSManagedObject
managedContext.deleteObject(managedObjectData)
}
} catch let error as NSError {
print("Detele all data in \(entity) error : \(error) \(error.userInfo)")
}
}
Usage:
self.deleteAllData("your_entityName")
Already seen in: https://stackoverflow.com/a/33931528/2894160
Best is delete the persistence storage and then add new one instead of looping each entity (if you want to delete all entities from coredata).
func deletePersistentStoreCoordinator () {
do {
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("YourDatabaseName.sqlite")
try self.persistentStoreCoordinator.destroyPersistentStoreAtURL(url, withType: NSSQLiteStoreType, options: nil)
try self.persistentStoreCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil)
}
catch{
}
}
Here is the code for deleting records from Core Data :
//Delete user info from local db
func deleteUserInfo() {
let context = appdelegate.managedObjectContext
let coord = appdelegate.persistentStoreCoordinator
let fetchRequest = NSFetchRequest(entityName: "User")
if #available(iOS 9.0, *) {
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
//let predicate = NSPredicate(format: "id == %#", key)
//fetchRequest.predicate = predicate
do {
try coord.executeRequest(deleteRequest, withContext: context)
}
catch let error as NSError {
//Error handling
}
catch {}
} else {
// Fallback on earlier versions
do {
let users: NSArray = try appdelegate.managedObjectContext.executeFetchRequest(fetchRequest)
for user in users {
appdelegate.managedObjectContext.delete(user)
}
try appdelegate.managedObjectContext.save()
} catch let error as NSError {
//Error handling
}
catch {}
}
}
I'm having problems implementing coredata in my project. it seems to be able to save but not to fetch. here's the code
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Utente", in: context)
let item = NSManagedObject(entity: entity!, insertInto: context)
var utente: Profilo? = nil
let vc = CustomTabBarController() as UIViewController
let vc1 = LoginController() as UIViewController
// Configure Fetch Request
do {
let request: NSFetchRequest<NSFetchRequestResult> = Profilo.fetchRequest()
let result = try context.fetch(request) as Profilo
utente = result as Profilo
print()
if utente?.type != nil {
if utente?.type == "students"{
print("students")
present(vc, animated: true, completion: nil)
}
if utente?.type == "parents"{
print("parents")
present(vc, animated: true, completion: nil)
}
if utente?.type == "teachers"{
print("teachers")
present(vc, animated: true, completion: nil)
}
} else {
print("variable type empty")
present(vc1, animated: true, completion: nil)
}
} catch {
let fetchError = error as NSError
print(fetchError)
}
i also get the error on the result line:
cannot invoke 'fetch' with an argument list of type (NSFetchRequest)
The syntax is supposed to be
let request: NSFetchRequest<Profilo> = Profilo.fetchRequest()
let result = try context.fetch(request) as! [Profilo] // returns always an array.
Consider that the default initializers CustomTabBarController() and LoginController() won't work.
As we agreed I'm posting my core data functions, they may not be the best way but they work in my project. My entity is called Goals.
// MARK: - Core data funcitons
func loadCoreData(){
goalsArray.removeAll()
//let request = NSFetchRequest<Goals>(entityName:"Goals")
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do{
let fetchRequest : NSFetchRequest<Goals> = Goals.fetchRequest() as! NSFetchRequest<Goals>
let sortDescriptor = NSSortDescriptor(key: "id", ascending: false)
fetchRequest.sortDescriptors = [sortDescriptor]
let result = try context.fetch(fetchRequest)
for result in result {
goalsArray.append(result)
print("Fetched result goaltitle is \(result.goalTitle!)")
}
tableView.reloadData()
print("I've fetched the results")
}
catch {
fatalError("Sthh")
}
}
func countCoreDataObjects()-> Bool{
//let request = NSFetchRequest<Goals>(entityName:"Goals")
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
do{
let fetchRequest : NSFetchRequest<Goals> = Goals.fetchRequest() as! NSFetchRequest<Goals>
let result = try context.fetch(fetchRequest)
if result.count == 0 {
return false
} else {return true
}
}
catch {
fatalError("Sthh")
}
}
func saveToCD(object: goalClassForPassing){
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Goals", in: context)
let goal = NSManagedObject(entity: entity!, insertInto: context) as! Goals
goal.goalTitle = object.goalName
goal.id = String(describing:Date())
goal.imagePath = object.imagePath
do {
try context.save()}
catch {
fatalError("couldn't save to core data")
}
goal.id = String(describing: Date())
goalObjectToSaveToCD?.id = String(describing: NSDate())
print(goalObjectToSaveToCD?.goalTitle)
print("Saved \(goal.goalTitle) - \(goal.id) - \(goal.imagePath) to Core Data")
loadCoreData()
}