Hi guys basically i have one one view that contains a UITableView, the table can add and delete entrys and saves its state in core datat stack. the view is a food diary and I have set up the view to keep all objects inserted and deleated persistent when the user add and removes a food entry. While this works for a single app session the table will not allow me to delete an entry when the i restart the app, but the last entered food is still displayed on screen.
If i try to delete the entry the application begins to crash. The core data entities are as follows Calories, Food and Exercise. I am gussing the fetch request located at the below of this code returns an array with zero objects and that why it will not me delete somthing that does not exists. I have posted the code below for somone to guide or help me out.
Thanks
import UIKit
import SwifterSwift
import CoreData
class DiaryView: UIViewController, UITableViewDataSource, UITableViewDelegate, NSFetchedResultsControllerDelegate, UITextFieldDelegate {
var userFoods:[String] = []
var userCalories:[String] = []
var userServings:[String] = []
var counter: Double = 0
var food = [Food]()
var calorie = [Calorie]()
@IBOutlet weak var userFoodTextField: UITextField!
@IBOutlet weak var userCaloriesTextField: UITextField!
@IBOutlet weak var userServingTextField: UITextField!
@IBOutlet weak var foodTable: UITableView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchUsersFood()
}
override func viewDidLoad() {
super.viewDidLoad()
foodTable.delegate = self
foodTable.dataSource = self
}
@IBAction func insertFoodAction(_ sender: Any) {
insertFoodAction()
}
}
extension DiaryView{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.food.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "foodCell") as! DiaryViewCustomCell
let foods = food[indexPath.row]
cell.foodnameLabel.text = foods.foodName
cell.calorieamountLabel.text = foods.calorieAmount + " " + "kcal"
cell.servingLabel.text = foods.servingAmount + " " + "servings"
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let lastCalorieAmount = calorie[indexPath.row]
let lastServingAmount = food[indexPath.row]
counter = lastCalorieAmount.totalCalorie.double()! - (lastServingAmount.servingAmount.double()! * lastServingAmount.calorieAmount.double()!)
deleteUserFood(at: indexPath)
saveLastestCalories(updatedValue: counter)
userFoods.remove(at: indexPath.row)
userCalories.remove(at: indexPath.row)
userServings.remove(at: indexPath.row)
foodTable.beginUpdates()
foodTable.deleteRows(at: [indexPath], with: .automatic)
foodTable.endUpdates()
view.endEditing(true)
}
}
func insertFoodAction() {
if userFoodTextField.text == "" || userCaloriesTextField.text == "" || userServingTextField.text == "" {
userFoodTextField.shake()
userCaloriesTextField.shake()
userServingTextField.shake()
}
else {
let indexPathFood = IndexPath(row: userFoods.count - 1, section: 0)
let indexPathCalories = IndexPath(row: userCalories.count - 1, section: 0)
let indexPathServing = IndexPath(row: userServings.count - 1, section: 0)
counter = counter + (userCaloriesTextField.text?.withoutSpacesAndNewLines.double())! * (userServingTextField.text?.withoutSpacesAndNewLines.double())!
saveUserFood()
saveLastestCalories(updatedValue: counter)
userFoods.append((userFoodTextField.text?.trimmed)!)
userCalories.append((userCaloriesTextField.text?.trimmed)!)
userServings.append((userServingTextField.text?.trimmed)!)
foodTable.beginUpdates()
foodTable.insertRows(at: [indexPathFood, indexPathCalories, indexPathServing], with: .automatic)
foodTable.endUpdates()
userFoodTextField.text = ""
userCaloriesTextField.text = ""
userServingTextField.text = ""
view.endEditing(true)
}
}
func saveUserFood() {
guard let applicationDelegate = UIApplication.shared.delegate as? AppDelegate else{return}
let managedContext = applicationDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Food", in: managedContext)!
let foods = Food(entity: entity, insertInto: managedContext)
foods.foodName = (userFoodTextField.text?.trimmed)!
foods.calorieAmount = (userCaloriesTextField.text?.trimmed)!
foods.servingAmount = (userServingTextField.text?.trimmed)!
foods.userFoodDate = Date()
do{
try managedContext.save()
food.append(foods)
} catch let error as NSError{
print("Could not save user food. \(error.userInfo)")
}
}
func deleteUserFood(at indexPath: IndexPath) {
guard let applicationDelegate = UIApplication.shared.delegate as? AppDelegate else{return}
let context = applicationDelegate.persistentContainer.viewContext
context.delete(food[indexPath.row] as NSManagedObject)
food.remove(at: indexPath.row)
do{
try context.save()
} catch let error as NSError{
print("Could not save user food. \(error.userInfo)")
}
}
func saveLastestCalories(updatedValue:Double) {
guard let applicationDelegate = UIApplication.shared.delegate as? AppDelegate else{return}
let managedContext = applicationDelegate.persistentContainer.viewContext
let entity = NSEntityDescription.entity(forEntityName: "Calorie", in: managedContext)!
let calories = Calorie(entity: entity, insertInto: managedContext)
calories.totalCalorie = updatedValue.int.string
calories.date = Date()
do{
try managedContext.save()
calorie.append(calories)
print(calories.totalCalorie)
} catch let error as NSError{
print("Could not save user food. \(error.userInfo)")
}
}
func fetchUsersFood() {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
let managedObjectContext = appDelegate.persistentContainer.viewContext
let fecthRequest = NSFetchRequest<NSManagedObject>(entityName: "Food")
fecthRequest.sortDescriptors = [NSSortDescriptor(key: "userFoodDate", ascending: false)]
do {
food = try managedObjectContext.fetch(fecthRequest) as! [Food]
print(food)
} catch let error as NSError {
print("Could not fetch data. \(error), \(error.userInfo)")
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 70.0
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
override var preferredStatusBarStyle: UIStatusBarStyle{
return .lightContent
}
}