RSS

Core Data Basics Part 4 – Relationships

19 Feb


Introduction

In this Part 4 of Core Data Basics I’ll demonstrate how to implement and use Relationships.  As we will be modifying an existing Core Data Model I will introduce Data Model Versioning.  The Tab Bar Controller will also be introduced to manage our growing Storyboard

Prerequisites

We follow on from Part 3 where we’ve already created a simple Storyboard app with delegation that Adds, Views, Edits and Deletes Core Data. Download the project from the end of Part 3 then extract and open it with Xcode.

Data Model Versioning

In Part 2 we created a simple Data Model that contained one entity called Role which contained a single attribute called name. To explain relationships I’ll need to update the Data Model. Remember this: Any time you intend to release an updated Data Model you should create a new version of the Data Model before you edit it.

To add a new version of the existing Data Model select Model.xcdatamodeld then click Editor > Add Model Version... Accept the default name of Model 2 then click Finish:

You will now have two versions of the Core Data Model so set the active version to Model 2 using File Inspector while Model.xcdatamodeld is selected:

The green tick should now be on Model 2:

To begin modifying the new version select Model 2.xcdatamodel then click Add Entity. Create a new Person entity with two attributes firstname and surname with a type of String:

Change Editor Style to Graph by toggling this little button:

You may need to drag the two entities apart to see them properly like this:

Configuring Relationships

To ask Core Data what Role a person is in (or what persons are in a role) we will need a relationship. Consider the following scenario:

A person (Tim Roadley) is in a role (Project Manager). On the flip side the role (Project Manager) is held by multiple people (Tim Roadley, Joe Blogs and Fred Random). You can see that those two points of view on the same relationship need different names – inRole and heldBy.  In addition to that it’s a one to many relationship as (Tim Roadley) can’t be in two roles at once… well, at least not in my model.  Create a relationship between the two entities by holding down Control and dragging a line between them.  Rename the newRelationship’s as follows:

Using Data Model Inspector edit heldBy so it is a To-Many Relationship:

You will now notice the double arrow indicating what direction the To-Many relationship is in:

Now that our Data Model has been updated we need to generate the Person NSManagedObject sub-class and regenerate the Role NSManagedObject sub-class. Select both the Person and Role entities, click Editor > Create NSManagedObject Subclass… then Create. Replace the existing Role files.

Inspect both Role and Person classes. There is the potential that one of them might not know about the other. To be on the safe side just regenerate both classes all over again making sure to overwrite the existing four files:

Run the app and it will crash with the error ‘The model used to open the store is incompatible with the one used to create the store‘ … awesome! We need to update the AppDelegate to put some extra options on the Persistent Store Coordinator.

Find this line of code in the persistentStoreCoordinator method of AppDelegate.m:

if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])

Change it to this:

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])

What that does is enable the automatic migration of old Data Models to the latest version! You can read more about it here.  Run the app again and it should not crash.

Re-using Hard Work

People Classes

We’ve already learned how to configure Add, View, Edit and Delete Role Table View Controllers in previous parts of the tutorial.  We need the same Table View Controllers for Person so why double up on work? Remember that:

  • RolesTVC forms a perfect template for PersonsTVC
  • AddRoleTVC forms a perfect template for AddPersonTVC
  • RoleDetailTVC forms a perfect template for PersonDetailTVC

We may as well leverage search and replace to create the Person classes.  Create a new PersonsTVC, AddPersonTVC and PersonDetailTVC class. It doesn’t matter how you create the classes as we replace their entire contents.  You should now have 6 new Person TVC files in the project.  You may want to start organising the folder structure a little too:

Time for some boring stuff:

  • Copy all the code from RolesTVC.h to PersonsTVC.h
  • Copy all the code from RolesTVC.m to PersonsTVC.m
  • Copy all the code from AddRoleTVC.h to AddPersonsTVC.h
  • Copy all the code from AddRoleTVC.m to AddPersonsTVC.m
  • Copy all the code from RoleDetailTVC.h to PersonDetailTVC.h
  • Copy all the code from RoleDetailTVC.m to PersonDetailTVC.m
  • Replace the word role with the word person in all of the new Person class files.
  • Replace the word Role with the word Person in all of the new Person class files.

Notice the lower/titlecase of role/Role and person/Person.  It’s critical you match case when doing the search and replace.  Just click the little magnifying glass so you can then tick the Match Case option:

After all that you should be left with a few errors to do with references to the name attribute in the Person entity which doesn’t exist. For each of those errors you can change name to firstname and make most of them go away.

As a part of that work change the sort descriptor in the setupFetchedResultsController method of PersonsTVC.m from name to firstname:

    // 4 - Sort it if you want
    request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"firstname" ascending:YES selector:@selector(localizedCaseInsensitiveCompare:)]];

Comment out the following lines in AddPersonTVC.h:

//@property (strong, nonatomic) IBOutlet UITextField *personNameTextField;

Comment out the following lines in AddPersonTVC.m:

//@synthesize personNameTextField;
//[self setPersonNameTextField:nil];
//person.firstname = personNameTextField.text;

Comment out the following lines in PersonDetailTVC.h:

//@property (strong, nonatomic) IBOutlet UITextField *personNameTextField;

Comment out the following lines in PersonDetailTVC.m

//@synthesize personNameTextField;
//self.personNameTextField.text = self.person.name;
//[self setPersonNameTextField:nil];
//[self.person setName:personNameTextField.text];

Run the app to ensure all the errors are gone. Just in case you got a bit lost here’s a copy of the code so far.

People Views

Open MainStoryboard.storyboard and duplicate everything on it by pressing Command-A then Command-D. Move the copied stuff up the top so it looks like the picture below:

We will reconfigure the stuff up the top to become the People views. You should know how to do this next stuff by now, so, for the copied views only perform the following:

  • Rename Roles Navigation Item Title to People
  • Rename Add Role Navigation Item Title to Add Person
  • Rename Role Detail Navigation Item Title to Person Detail
  • Set the Reuse Identifier of the People Prototype Cell to Persons Cell
  • Rename Add Person Table View Section Header from Role Name to First Name
  • Copy/Paste the Table View Section – First Name into its containing Table View.
  • Rename copied Table View Section Header from First Name to Surname
  • Rename Person Detail Table View Section Header from Role Name to First Name
  • Copy/Paste the Table View Section – First Name into its containing Table View.
  • Rename copied Table View Section Header from First Name to Surname
  • Rename the Segue between People and Add Person to Add Person Segue
  • Rename the Segue between People and Person Detail to Person Detail Segue
  • Set the Class of the People Table View Controller to PersonsTVC
  • Set the Class of the Add Person Table View Controller to AddPersonTVC
  • Set the Class of the Person Detail Table View Controller to PersonDetailTVC
The Person views should new resemble this:
The First Name and Surname Text Fields need to be linked to the underlying classes of the views they’re found on (AddPersonTVC.h and PersonDetailTVC.h).  Use the same procedure used in Part 2 to link this up. As a reminder swap to Assistant Editor then ensure you’re viewing the correct underlying class (see image below for how to change). Hold Control and drag from each Text field to the to the respective class header, call the new properties personFirstnameTextField and personSurnameTextField. If you were successful you will have created two new properties with little grey dots to the left of them that indicate a connection to a view. Don’t forget you need to do this for both AddPersonTVC.h and PersonDetailTVC.h:
Add the following code to the save method of AddPersonTVC.m under the commented out lines:
    person.firstname = personFirstnameTextField.text;
    person.surname = personSurnameTextField.text;
Add the following code to the viewDidLoad method of PersonDetailTVC.m under the commented out lines:
    self.personFirstnameTextField.text = self.person.firstname;
    self.personSurnameTextField.text = self.person.surname;
Add the following code to the save method of PersonDetailTVC.m under the commented out lines:
    self.person.firstname = self.personFirstnameTextField.text;
    self.person.surname = self.personSurnameTextField.text;

Remove the old references to roleNameTextField from the Outlets of the Add Person and Person Details Table View Controllers:

Edit the // Configure the cell … code in cellForRowAtIndexPath method of PersonsTVC.m:

    // Configure the cell...
    Person *person = [self.fetchedResultsController objectAtIndexPath:indexPath];
    NSString *fullname = [NSString stringWithFormat:@"%@ %@", person.firstname, person.surname];
    cell.textLabel.text = fullname;
    //cell.textLabel.text = person.firstname;

Tab Bar Controllers

Now it’s time to bring it all together with a Tab Bar Controller so drag one on to the canvas to the left of the existing stuff. Delete the two views that come with it.  Hold down Control and drag a line to both existing Navigation controllers to create a viewControllers relationship Segue. Set the Tab Bar Controller as the initial view controller so it is the first view shown when the app launches (you may need to un-tick one of the Navigation Controllers as also being the initial view controller. At a very high level the canvas should look like this:
On each Navigation Controller double click the little icon to set the Title of each Bar Item.  Call one Roles and the other People.  If you look at the Tab Bar Controller it will now show these names automatically.  It’s important to note the order from left to right as 0,1 .. etc as we will be referring to this index in code soon:

One of the final things to do now is to configure the AppDelegate.m to pass the managed object context through to each of the view controllers’ managedObjectContext properties. Without this we will break Core Data. Ensure the following code is in AppDelegate.m:

#import "PersonsTVC.h"
#import "RolesTVC.h"

Edit the didFinishLaunchingWithOptions method of the AppDelegate.m as follows:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // The Tab Bar
    UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
 
    // The Two Navigation Controllers attached to the Tab Bar (At Tab Bar Indexes 0 and 1)
    UINavigationController *personsTVCnav = [[tabBarController viewControllers] objectAtIndex:0];
    UINavigationController *rolesTVCnav = [[tabBarController viewControllers] objectAtIndex:1];
 
    // The Persons Table View Controller (First Nav Controller Index 0)
    PersonsTVC *personsTVC = [[personsTVCnav viewControllers] objectAtIndex:0];
    personsTVC.managedObjectContext = self.managedObjectContext;    
 
    // The Roles Table View Controller (Second Nav Controller Index 0)
    RolesTVC *rolesTVC = [[rolesTVCnav viewControllers] objectAtIndex:0];
    rolesTVC.managedObjectContext = self.managedObjectContext;
 
    //NOTE: Be very careful to change these indexes if you change the tab order
 
    // The following stuff was commented out since we're using a Tab Bar Controller
    //UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
    //RolesTVC *controller = (RolesTVC *)navigationController.topViewController;
    //controller.managedObjectContext = self.managedObjectContext;
    return YES;
}

You should now be able to run the app and tab switch between Adding, Viewing, Editing and Deleting both People and Roles!

Relationships in Action

The goal of my example relationship is to show people’s roles on the People table. To show more than one data value on the People table, change the Table View Cell Style of the People Prototype Cells to Subtitle:

To associate a person with a role I was going to use a UIPickerView however found that it is quite an art to get one of those displaying properly with Core Data on all devices.  I will save that for another tutorial and for now settle on creating a Person’s Role Table View Controller backed by a new class called PersonRoleTVC.  PersonRoleTVC uses techniques you should by now be used to from previous parts of this tutorial such as passing a context and delegation.  Create a new PersonRoleTVC class then replace all the code in PersonRoleTVC.h with the following:

#import <UIKit/UIKit.h>
#import "Role.h"
#import "CoreDataTableViewController.h" // so we can fetch
 
@class PersonRoleTVC;
@protocol PersonRoleTVCDelegate
- (void)roleWasSelectedOnPersonRoleTVC:(PersonRoleTVC *)controller;
@end
 
@interface PersonRoleTVC : CoreDataTableViewController
@property (nonatomic, weak) id  delegate;
@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
@property (strong, nonatomic) Role *selectedRole;
 
@end

Also replace all of the code in PersonRoleTVC.m with the following:

#import "PersonRoleTVC.h"
 
@implementation PersonRoleTVC
@synthesize fetchedResultsController = __fetchedResultsController;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize delegate;
@synthesize selectedRole;
 
- (void)setupFetchedResultsController
{
    // 1 - Decide what Entity you want
    NSString *entityName = @"Role"; // Put your entity name here
    NSLog(@"Setting up a Fetched Results Controller for the Entity named %@", entityName);
 
    // 2 - Request that Entity
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
 
    // 3 - Filter it if you want
    //request.predicate = [NSPredicate predicateWithFormat:@"Person.name = Blah"];
 
    // 4 - Sort it if you want
    request.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"name"
                                                                                     ascending:YES
                                                                                      selector:@selector(localizedCaseInsensitiveCompare:)]];
    // 5 - Fetch it
    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                        managedObjectContext:self.managedObjectContext
                                                                          sectionNameKeyPath:nil
                                                                                   cacheName:nil];
    [self performFetch];
}
 
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [self setupFetchedResultsController];
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 
    self.selectedRole = [self.fetchedResultsController objectAtIndexPath:indexPath];
    NSLog(@"The PersonRoleTVC reports that the %@ role was selected", self.selectedRole.name);
    [self.delegate roleWasSelectedOnPersonRoleTVC:self];
 
}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Person Role Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
 
    // Configure the cell...
    Role *role = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = role.name;
 
    return cell;
}
 
@end

Open up MainStoryboard.storyboard then:

  • On the Person Detail Table View Controller copy/paste the Surname Table View Section into the same Table View.
  • Rename the copied Table View Section to Role then delete the UITextField within it.
  • Drag a new Table View Controller to the canvas to the right of the Person Detail Table View Controller.
  • Drag a Push Segue from the Role Table View Cell to the new table view and rename the Segue Identifier to Person Role Segue.
  • Rename the new Table View Controller Navigation Item Title to Person’s Role.
  • Set the Reuse Identifier of the Person’s Role Prototype Cells to Person Role Cell.
  • Set the Custom Class of the Person’s Role Table View Controller to PersonRoleTVC.

The storyboard should look a little like this:

Use Assistant Editor to Contol-drag a new property from the Role Table View Cell (from Person Detail table) to the PersonDetailTVC.h file.  Call the new property personRoleTableViewCell. This should create a new connected property for you automatically in PersonDetailTVC.h as follows:

@property (strong, nonatomic) IBOutlet UITableViewCell *personRoleTableViewCell;

PersonDetailTVC.h also needs to know what a Role is so it can store the selected role for the save.  To get that info back from PersonRoleTVC it needs to be its delegate too.  Edit/add to PersonDetailTVC.h as follows:

#import "Role.h"
#import "PersonRoleTVC.h"
@interface PersonDetailTVC : UITableViewController <PersonRoleTVCDelegate>
@property (strong, nonatomic) Role *selectedRole;

Of course You will now have to add a few things to PersonDetailTVC.m like this:

@synthesize selectedRole;

…and this (remove existing save method):

- (IBAction)save:(id)sender
{
    NSLog(@"Telling the PersonDetailTVC Delegate that Save was tapped on the PersonDetailTVC");
 
    self.person.firstname = self.personFirstnameTextField.text; // Set Firstname
    self.person.surname = self.personSurnameTextField.text; // Set Surname
    [self.person setInRole:self.selectedRole]; // Set Relationship!!!
    [self.managedObjectContext save:nil];  // write to database
    [self.delegate theSaveButtonOnThePersonDetailTVCWasTapped:self];
}
 
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender  // !
{
    if ([segue.identifier isEqualToString:@"Person Role Segue"])
	{
        NSLog(@"Setting PersonDetailTVC as a delegate of PersonRoleTVC");
        PersonRoleTVC *personRoleTVC = segue.destinationViewController;
        personRoleTVC.delegate = self;
        personRoleTVC.managedObjectContext = self.managedObjectContext;
	}
    else {
        NSLog(@"Unidentified Segue Attempted!");
    }
}
 
- (void)roleWasSelectedOnPersonRoleTVC:(PersonRoleTVC *)controller
{
    self.personRoleTableViewCell.textLabel.text = controller.selectedRole.name;
    self.selectedRole = controller.selectedRole;
    NSLog(@"PersonDetailTVC reports that the %@ role was selected on the PersonRoleTVC", controller.selectedRole.name);
    [controller.navigationController popViewControllerAnimated:YES];
}

The very last thing you have to do is add the following to the cellForRowAtIndexPath method of the PersonsTVC.m file:

cell.detailTextLabel.text = person.inRole.name;

Here’s the final result:

That’s it! Stay tuned for Part 5 where I’ll discuss pre-loading default data.

Here’s the source code so far

If you liked this tutorial or found something wrong with it please let me know!

If you want to support my work and have an iPad please consider purchasing iSoccer *wink*

-Tim

Go to Part 5 or the Tutorials Index


Be Sociable, Share!
     

    About Tim Roadley

    I'm a senior analytics software consultant at eMite Pty Ltd primarily focused on delivering business intelligence dashboards, currently for one of Australia’s major banks. I'm also working on a revamped version of eMite's iOS App for release under iOS 7. Prior to eMite, I was Infrastructure Manager at Cuscal Pty Ltd where I was heavily involved in designing and implementing a payments switch that drives 1300+ ATM’s Australia wide. I have several apps on the App Store, including Teamwork, iSoccer and now Grocery Dude and Grocery Cloud. In my down time I enjoy spending time with my wonderful wife Tracey and two lovely children Tyler and Taliah.
    41 Comments

    Posted by on February 19, 2012 in iOS Tutorials

     

    41 Responses to Core Data Basics Part 4 – Relationships

    1. adrian phillips

      February 27, 2012 at 2:25 am

      cool work tim. thanks for a great tutorial man. very useful and so easy to follow.

      adrian

       
    2. Abhishek Sonawane

      March 2, 2012 at 7:42 pm

      Hey Tim,
      Your tutorials are absolutely fantastic to follow.

      I had a small question, how can you implement a single search bar for your ROLE table as well as PERSON table?

      It will be great if you add a tutorial for that too.

      Thank you
      Abhishek.

       
    3. Tim Roadley

      March 3, 2012 at 10:23 am

      Hi Abhishek,

      I’m glad you’re liking the tutorials. That search bar tutorial is a great idea, I’ll look into that and make one next week some time!

      Tim

       
    4. Abhishek Sonawane

      March 3, 2012 at 12:39 pm

      Hi Tim,

      I am getting a very strange error while compiling my project saying “uncategorized compilation error”. I am trying to resolve it since yesterday, I could not find any help for that.

      Can I mail you the .zip file of it? Can you plz check what exactly is going wrong?

      It will be a huge help.

      Thank you in advance. And yes, I will be waiting for your SEARCH BAR tutorial.

      Abhishek.

       
    5. Bill Spivey

      March 10, 2012 at 2:43 am

      I’m still with u Tim, but I segued to adapting your person/role scenario to a database idea of my own that has some of the same structural ideas. I’ve made a 1000 mistakes along the way, but my project is at about this part 4 level feature set now. I feel like maybe I could one day begin to understand how all this works. How did you ever teach yourself to do this? :) I’ve followed Paul Hegarty’s lectures myself, and haven’t gotten nearly the comprehension you seem to have gained.

       
    6. Tim Roadley

      March 10, 2012 at 1:09 pm

      Bill,

      Paul Hegarty’s lecture sets are good to gain the overall concepts.

      To continue the learning I write these tutorials. A lot of the time I’ll start a tutorial with no idea how to achieve the tutorial’s goal. It probably just forces me to think a certain way and double check my assumptions.

      The trick is really just to keep at it. You might see a nice end result tutorial now … don’t think it’s not as a result of 9283432 errors along the way :)

       
    7. Maik Hertha

      March 20, 2012 at 12:42 am

      Hi Tim,

      Nice tutorial collection, well balanced between boiler blade code and details for core data ;).

      A hint – you use CoreDataTableViewController as a base class for PersonRoleTVC. So you don’t need to define a property fetchedResultsController and have not to call performFetch, because its automatically called in the setter for fetchedResultsController in the base class.

       
    8. Terry

      April 1, 2012 at 2:28 am

      when working through this part of your excellent tutorial, I added code into the TVC classes to directly fetch the managed object context rather than having it set in the app delegate code. The advantages are that it is now independent of the tab index order, doesn’t need to have app delegate refer to each view controller class and allows for additional view controller classes to be added. The added code is (in view controller .m):

      #import “AppDelegate.h”

      AppDelegate *app = [UIApplication sharedApplication].delegate;
      self.managedObjectContext = app.managedObjectContext;

      seems to work ok.

       
      • Tim Roadley

        April 1, 2012 at 6:52 am

        Hi Terry,

        I originally set up the view controllers like that however then I read this article by Apple:

        http://developer.apple.com/library/ios/documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/stack.html

        The section in particular to read is titled
        ‘Getting a Managed Object Context’, ‘On iPhone’.

        It says (after some other initially confusing points) that ‘It’s typically the responsibility of the application delegate to create a context to pass to the first view controller that’s displayed.’. In our case, the first views through the tab controller.

        The hassle with the tab bar is annoying yes however it ensures that every view is aware of the exact same context. Even if the app hierarchy ends up with hundreds of views you will have only had to of passed the context to each tab. From then on its simple to pass the context between views via segues etc.

        At the end of the day if it works for you that’s great :)

        Cheers

         
    9. Terry

      April 2, 2012 at 12:46 am

      Tim – thanks for the comment. I read the article you referenced and it does make sense, sort of, especially in the case where you might have more than one context so the view receives the appropriate context.

      Regarding the tab messiness, I guess you could define a simple protocol for passing the context, have all your view controllers that are in the tabs implement this protocol and then the app delegate could just cycle through the top level vcs, casting them to the protocol to pass the context, so that you wouldn’t have to include all of the classes explicitly and have dependence on the index order and, if you add more, you don’t have to change the app delegate code. (Possibly that could also be extended so the prepareseque code could use the same approach.) … or not.

       
    10. James

      April 12, 2012 at 5:40 am

      Hi Tim,

      I’ve spent like hundrets of hours looking up for Core Data training. I’ve seen 10+ tutorials, blogs, etc. I’ve never seen such a well organized tutorial. Thanks a lot for the time and effort. I’m also a fan of Paul’s. However, his taget audience is computer science students, so I don’t get half of it and I’ve to watch it over and over with the slides by my side…

      One thing though about this particular tutorial. It would be really nice if you could explain in more detail how to hook up the relationships. I believe it would round up the tutorial very nicely.

      Thanks again!

       
    11. alexander sharma

      April 17, 2012 at 10:14 am

      Hi

      How can I have many to many relationship.

      i.e. one name can have multiple roles then i want to display the multiple roles.

      e.g. alex
      role developer, accountant, tester

      and i want to display that too.

      thanks please let me know.

      please email me at alexander.sharma@gmail.com

       
      • Tim Roadley

        April 25, 2012 at 8:27 am

        You just need to generate the string to put all the roles together, something like this:

        NSString *manyRoles = @””
        for (Role *role in person.role)
        {
        manyRoles = [NSString stringWithFormat@"%@, %@",manyRoles, role.name]
        }

        Of course you would need to play with it a bit to get it right

         
    12. MIchael

      April 18, 2012 at 11:03 am

      Hey Tim! I’ve been loving the last 3 parts of this tutorial. They’ve been exactly what I’ve needed since I’m quite a newbie.

      What I’m working on is a bit simpler than what you’ve made in part 4, and I was wondering if there was a way to just add the “role” subtitle to what I have from part 3. I just have 3 different things I want to choose from as subtitles, and I don’t necessarily need to use the tab bar or change the entire application from Roles to People.

      I’m definitely not asking you to write up an entire app for this, but maybe a few hints so I could try to get this done.

      Thanks so much and let me know if I can provide any more information. I’m just new at iPhone development and I need a little bit of help. :)

       
    13. alexander sharma

      April 19, 2012 at 8:27 am

      Hi

      Can someone show me where the code is for the search in core data e.g. I want to search for all roles of c++ developer.

      i.e. how does the query look in core data for that

      Thanks

       
    14. Daniel Bates

      April 25, 2012 at 11:22 am

      I don’t seem to have a data model editor that shows a way to make many to one relationships. All I see is Entity, Relationship, Destination, Inverse. There are no other options.

       
    15. Rubs

      May 24, 2012 at 7:00 am

      Hey Tim,
      I am new to ap dev. I love your tutorials. I tried the Stanford course and found it hard to get excited about a calculator ap and understand where he was going half the time…then he would go back and say “We don’t need this anymore” and delete stuff…making it quite an up hill battle for a total noob.

      I stared with Rory Lewis books to get my feet wet and now onto your stuff and finding I understand more n more every day.

      Is there a way to pm you about how I want to augment this project for an ap I am working on?

      Thanks

       
    16. Graham Gardiner

      June 3, 2012 at 2:13 am

      Hi Tim
      I was wondering if you may be able to help me I have done your core data tutorial which is really been both rewarding and really easy to follow. My next step is to take the Role table and list all the people in that role on one table ie programmer – John Smith, Frank Brown, George Benson etc and if you then tap any one of there names it will then open that persons details on the persondetails table.

      I hope you can have a look into this and see what you can do even if you can help with the call code I know it would involve another tableviewcontroller a new class and a segue from the Role table with a button to it

      I look forward to any help you may give.

      thank you and best regards

      Graham Gardiner

       
    17. Zune Moe

      July 10, 2012 at 6:42 am

      Hi Tim,
      I used another table view controller to connect two views (people and roles) instead of tab bar controller because i want to add some more views later.
      But when I transition from my main table view to whatever subviews (people or roles) i got an error at setupFetchedResultsController method at step 5.

      I’m looking forward to you help.

      thank you.
      with regards.

       
    18. Carl Roberts

      July 20, 2012 at 10:36 pm

      These are really fine tutorials and you explain them clearer than any book i’ve looked at. I studied core data as part of my dissertation at Uni and these tutorials are teaching me how to use core data with storyboards. It’s also teaching me how to use storyboards because I’ve always turned my nose up at them being an too used to the old ‘xib’ files. Thank you for making them.

       
    19. arrrr

      July 23, 2012 at 7:21 pm

      would be nice if you could add the

      “Notice the lower/titlecase of role/Role and person/Person. It’s critical you match case when doing the search and replace. Just click the little magnifying glass so you can then tick the Match Case option:”

      before all those copy and replace commands ;-)

       
    20. Eve Lima

      July 29, 2012 at 12:52 am

      Changes to persistentStoreCoordinator method didn’t avoid crash.. XCode(4.3.3) still couldn’t find new data model.

       
    21. Idan

      August 27, 2012 at 5:34 pm

      Hi Tim,

      Well built tutorial. Really nice work, and great diving into all details.
      One little thing to consider:
      Instead of all those find/replace, user inheritance. This specific case is a classic demonstation of the power of inheritance and you should really use it. Build something like an abstract TVC for Core Data handling, and each NSManageObject subclass will have its own TVC that inherits from this abstract. all you need are different names for properties.

      Keep up the good work, I believe you’ve created some iOS developers ;)

       
    22. Umut

      September 4, 2012 at 9:04 pm

      its so cool and good. thanx

       
    23. Umut

      September 5, 2012 at 2:03 am

      Hi Tim,
      I got an error like this. What can i do?

      2012-09-04 19:01:29.628 Staff Manager[1380:fb03] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘keypath name not found in entity ‘

       
    24. Barb

      September 30, 2012 at 9:57 am

      Great tutorials so far! Thank you! I’m using Xcode 4.2 and am unable to set the new Model as my current one. Xcode 4.2 doesn’t have a “current” drop-down for the data model. Any suggestions? In the meantime, I’m just going to download your code for this tutorial to get past this issue.

      Thanks!

       
    25. Alejandro

      November 24, 2012 at 3:23 am

      Tim, great tutorial! Thank you so much.
      I am following your tutorial to build my own project. Even though mostly similar, when I click on the Role to EDIT it, I want to land on a UITabBarViewController that has as its first tab the Role Details, but the other Tabs will offer additional fields (to be stored in different Entities) that will all be related to the selected Role to edit. How do you suggest I go about this?
      Thanks!

       
    26. JP

      January 6, 2013 at 10:21 pm

      Great tutorials, in this one I am not getting the Role back on the person detail page when I want to edit it. Could you give me pointers as to what I have missed or should add?

       
      • JP

        January 6, 2013 at 10:27 pm

        Never mind me, I figured it out :)

        I’ve added to PersonDetailTVC.m in the viewDidLoad

        self.personRoleTableViewCell.textlabel.text = self.person.inRole.name;

        Seems to work…

         
        • Paula

          November 20, 2013 at 4:06 am

          Had the same problem! It worked! Thanks! :)

           
    27. ericsoco

      February 6, 2013 at 4:50 pm

      If you run into a “can’t find model for source store” error when trying to build/run, try deleting your app from your emulator and then run again. Not clear on this but I believe the issue has to do with a stale database in the app, and creating a new data model without properly versioning breaks the association with that database.

       
    28. Asaf

      May 25, 2013 at 8:56 am

      Hi,
      just i want to tell you, this tutorial is the best i found in the internet.
      finally i understood CoreData.

      and, i want to suggest
      Add into the PesronDetail.m
      into ViewDidLoad:

      self.PersonRoleTableViewCell.textLabel.text = self.perso.inRole.name;

      its a little bug that when user click on any Person (that have an Role) the Role name cannot appear in the PersonDetailTVC under Role.

      Tim, please help with more Tutorials.
      Would love to see more guides in various Topics of IOS Dev.

      Thanks

       
    29. Alex Zavatone

      September 7, 2013 at 2:05 am

      Great, great, great tutorial. Now, if I could only find out why the PersonsTVC is losing its MOC, and crashing on save, I’d be happy. Thanks for posting the finished working code. Time to diff the files.

       
    30. Steve

      September 17, 2013 at 4:04 am

      I would personally never send a reference to the delegating object in the tightly coupled way this tutorial shows. There’s simply no reason to. You can access the current VC on the stack by simply calling self.navigationController. So, to pop it you can do [self.navigationController popToViewController:self]; from the delegate. We always know who the top viewController is on the stack after all. This keeps it more generic, less tightly coupled.

       
      • Tim Roadley

        September 17, 2013 at 6:42 am

        I agree, and there’s actually no need to tie the managed object context to the view anyway. It unnecessarily complicates things.

        A much better way is shown in my book, to be release early next month.

         
      • Paula

        November 20, 2013 at 4:18 am

        Can you tell me what line to change so I can try it. I’m a Newbie. Thanks

         
    31. HuongNV

      October 18, 2013 at 6:45 pm

      Thanks Tim Roadley
      I have a question and problem here:
      Base on your tutorial, I create my project:
      – Entity Employee: name, gender, age, height, haircolor, comment, country
      – Entity Report: note, time, location
      It’s a one to many core Data like you. One Employee have many report
      I insert Employee to core data everything ok.
      When i create a form to insert Report. It get error something cannot find entity “Report”
      But i’m already create Report.h and Report.m
      Pls help me. Thanks a lot

       
    32. rao

      January 9, 2014 at 1:44 am

      Heartfelt Thank You for your kind graciousness in openly sharing your hard-earned knowledge :-)
      Your crystal-clear tutorial helped me add a Tab Bar Controller to a working Master-Detail app.

       

    Leave a Reply