Search code examples
swiftuitableviewcore-dataattributesnsfetchedresultscontroller

Calling a Core Data attribute through a relationship


I have two Entities as depicted in the image below:

enter image description here

Food and Restaurant.

I know the naming is a bit off for now, but basically, I'm building up a list of Food items. A user will add in a new entry with the name of the food and the name of the restaurant. I'm at the very early stages of development.

So in the AddViewController, and in the save method, I have:

if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
            foodEntry = FoodManagedObject(context: appDelegate.persistentContainer.viewContext)
            foodEntry.nameOfFood = foodNameTextField.text
            foodEntry.restaurantName?.nameOfRestaurant = restaurantNameTextField.text

With a variable declared:

var foodEntry:FoodManagedObject!

In the TimelineView, using NSFetchedResultsController, I'm fetching for the FoodManagedObject and able to display the name of the food in the label. However, the name of the restaurant doesn't display.

So, I'm fetching appropriately:

let fetchRequest: NSFetchRequest<FoodManagedObject> = FoodManagedObject.fetchRequest()
        let sortDescriptor = NSSortDescriptor(key: "nameOfFood", ascending: true)
        fetchRequest.sortDescriptors = [sortDescriptor]

        if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {
            let context = appDelegate.persistentContainer.viewContext
            fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
            fetchedResultsController.delegate = self

            do {
                try fetchedResultsController.performFetch()
                if let fetchedObjects = fetchedResultsController.fetchedObjects {
                    foods = fetchedObjects
                }
            } catch {
                print(error)
            }
        }

and in the cellForRow:

cell.foodNameLabel.text = foods[indexPath.row].nameOfFood

cell.restaurantLabel.text = foods[indexPath.row].restaurantName?.nameOfRestaurant

I get no errors, but the name of the restaurant never displays.

Foods is:

var foods:[FoodManagedObject] = []

So I've tried adding in an attribute called theRestaurant into the Food Entity and that works, but calling through a relationship never seems to work.

Am I missing something obvious here?


Solution

  • You're creating relations between the objects, not of their values It means, that you must assign already existing restaurant entity object or create the new one when you're saving the new food object. You can't just assign object values without an initialisation of the restaurant object.

    E.g.

    foodEntry = FoodManagedObject(context: appDelegate.persistentContainer.viewContext)
    foodEntry.nameOfFood = foodNameTextField.text
    
    // Here you must to load existing Restaurant entity object from database or create the new one        
    let restaurant = RestaurantManagedObject(context: appDelegate.persistentContainer.viewContext)
    restaurant.nameOfRestaurant = restaurantNameTextField.text
    
    foodEntry.restaurantName = restaurant // Object instead of value
    

    Or if you already have some list of restaurants, than just add the new food object to one of them