0

Hi fellow developers,

I have an app in its early stages utilising Core Data.

The premise is simple: Add in restaurants, save it to Core Data and display it. So I have an AddEntry with a bunch of textFields - the user fills those in, clicks Save and it gets saved to Core Data. In the main view, the data gets displayed using NSFetchedResultsController and UITableViewController. That works well.

I have a DetailView which looks exactly like the AddEntry and is a segue away from the Timeline; click a cell and it goes to a DetailView displaying all of the information populated in.

I'm trying to edit entry here, by for example, changing the name of the food, or the restaurant (textFields) and save it to Core Data. Saving works, but what I've realised is that it actually doesn't override the entry, it just creates a brand new entry.

I totally understand why it's doing that - I'm creating a new instance, etc, but I'm not 100% sure what to do.

In a previous app, I used a technique to:

  • perform a fetch request
  • create an array of fetchRequets
  • if the entry doesn't exist, create it
  • if it does, return it.

That code (written in Objective C) is below:

Person *person = nil;

// Creating a fetch request to check whether the person already exists, calling from the Add/DetailViewController.
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];
request.predicate = [NSPredicate predicateWithFormat:@"name = %@", name];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];
request.sortDescriptors = [NSArray arrayWithObject:sortDescriptor];

NSError *error = nil;
NSArray *people = [context executeFetchRequest:request error:&error];
if (!people)
{
    // Handle Error
}
else if (![people count])
{
    // If the person count is 0 then create it
    person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
    person.name = name;
}
else
{
    // If the object exists, just return it
    person = [people lastObject];
}
return person; 

I'm now doing this new application in Swift, and I'm wondering:

  • is this the right approach? To fetch request, create new entry if it doesn't exist, or return it if it does?
  • In my Save code, I don't seem to have "insertNewObjectForEntityForName" as part of my new Swift code - am I missing that?

Here's my "save" code.

if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {


        // I am creating an instance of both the food and restaurant from the Food and Restaurant Managed Objects.
        foodEntry = FoodManagedObject(context: appDelegate.persistentContainer.viewContext)
        restaurantEntry = RestaurantsManagedObject(context: appDelegate.persistentContainer.viewContext)
        foodEntry.nameOfFood = foodTextField.text
        appDelegate.saveContext()
        print("the food name is \(String(describing: foodEntry.nameOfFood))")
    }

Any thoughts are welcomed.

Update

The answer provided the information I needed to get this working, but for my own understanding, I need to figure out something and see if I can understand what's going on.

In the video provided and the other solutions, when adding a new entry to CoreData, the code insertNewObject(forEntity: "Entity" into: managedObjectContext) is provided.

In my application, the code below does the job of creating a new entry in CoreData (I can see because the NSFetchedResultsController provides the results). Why does my code work, what is my code actually doing differently from insertNewObject(forEntity: "Entity" into: managedObjectContext) and should I actually just be using insertNewObject(forEntity: "Entity" into: managedObjectContext)?

if let appDelegate = (UIApplication.shared.delegate as? AppDelegate) {

            // I am creating an instance of both the food and restaurant from the Food and Restaurant Managed Objects.
            foodEntry = FoodManagedObject(context: appDelegate.persistentContainer.viewContext)
            restaurantEntry = RestaurantsManagedObject(context: appDelegate.persistentContainer.viewContext)

            // I am firstly setting the name to the nameTextField. That's easy.
            foodEntry.nameOfFood = foodNameTextField.text
            foodEntry.type = restaurantTypeTextField.text
            // I am then setting the restaurant Name using the restaurnt Managed Object and then assigning the foodEntry.restaurant (the relationship) to the entry. This is a trick from Envylope and is what got the restaurantName to display on the Timeline. The same is done for the address.
            restaurantEntry.nameOfRestaurant = restaurantNameTextField.text
            restaurantEntry.address = restaurantLocationTextField.text
            foodEntry.restaurant = restaurantEntry
amitsbajaj
  • 1,304
  • 1
  • 24
  • 59

0 Answers0