- Home
- >> Nerd Digest
- >> iOS
-
How to use Core Data in iOS Part 2?
over 8 years ago
Hi Readers!
This blog includes the advance topic of Core Data which is relationship between two entities. If you are not familiar with the concept of Core Data you can view the link to understand the Core Data (Part 1). Link include the information about how to create entity and to perform insert,delete,update operations in the same.In 2nd part of this blog, we will learn how to implement relationship with the help of Core Data. Please download the sample project from the link as we are going to use the same project to create relationship.
Firstly, we will create another entity named as Company, once it is created we will create a relationship between the Employee entity and new created entity Company. Below are the screenshots of creation of new entity and simultaneously creating a relationship.Relationship which we are going to include in this application is many to one. As a single company can have any number of employees so the relationship between Employee entity and Company entity is many to one. So while creating relationship always explain the relationship in terms of suitable names. As in below snapshot it is clearly visible that relationship column include belongsToCompany name, destination means the entity with whom relationship is applicable and inverse include the property names as hasEmployees. In this way we can create relationship between two entities.
Here in another entity which is destination will automatically get the filled information of relationship as it is already connected from previous entity.
Now the changes done in storyboard will be shown with the help of screenshots. Changes in previous controllers are as follows:-
In EmployeeListViewController an another button is added on the top to add new company.
In AddCompanyViewController new company can be added which will be available at the time of adding employee as which employee belongs to which company.
In AddEmployeeDetailViewController an another textfield is added which provides a list of company with the help of picker.
Now the whole view of storyboard will be visible in this way as shown in below screenshot.
Now coding part will be started from here. As we are creating a new entity so we have to create new subclass also as created
in previous part. As we are doing changes in Employee entity also so we need to create subclasses again so delete the previous subclasses of Employee entity and create new subclasses of both entity. So after creation of subclasses all properties will be shown in the following way:-Subclasses of Employee entity is as follows:-
Employee.h #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @class Company; NS_ASSUME_NONNULL_BEGIN @interface Employee : NSManagedObject // Insert code here to declare functionality of your managed object subclass @end NS_ASSUME_NONNULL_END #import "Employee+CoreDataProperties.h" Employee.m #import "Employee.h" #import "Company.h" @implementation Employee // Insert code here to add functionality to your managed object subclass @end Employee+CoreDataProperties.h #import "Employee.h" NS_ASSUME_NONNULL_BEGIN @interface Employee (CoreDataProperties) @property (nullable, nonatomic, retain) NSString *employee_Designation; @property (nullable, nonatomic, retain) NSString *employee_Name; @property (nullable, nonatomic, retain) NSString *employee_Salary; @property (nullable, nonatomic, retain) Company *belongsToCompany; @end NS_ASSUME_NONNULL_END Employee+CoreDataProperties.m #import "Employee+CoreDataProperties.h" @implementation Employee (CoreDataProperties) @dynamic employee_Designation; @dynamic employee_Name; @dynamic employee_Salary; @dynamic belongsToCompany; @end
Subclasses of Company entity is as follows:-
Company.h #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> @class Employee; NS_ASSUME_NONNULL_BEGIN @interface Company : NSManagedObject // Insert code here to declare functionality of your managed object subclass @end NS_ASSUME_NONNULL_END #import "Company+CoreDataProperties.h" Company.m #import "Company.h" #import "Employee.h" @implementation Company // Insert code here to add functionality to your managed object subclass @end Company+CoreDataProperties.h #import "Company.h" NS_ASSUME_NONNULL_BEGIN @interface Company (CoreDataProperties) @property (nullable, nonatomic, retain) NSString *company_Name; @property (nullable, nonatomic, retain) NSSet<Employee *> *hasEmployees; @end @interface Company (CoreDataGeneratedAccessors) - (void)addHasEmployeesObject:(Employee *)value; - (void)removeHasEmployeesObject:(Employee *)value; - (void)addHasEmployees:(NSSet<Employee *> *)values; - (void)removeHasEmployees:(NSSet<Employee *> *)values; @end NS_ASSUME_NONNULL_END Company+CoreDataProperties.m #import "Company+CoreDataProperties.h" @implementation Company (CoreDataProperties) @dynamic company_Name; @dynamic hasEmployees; @end
Modification in StringDeclaration class according to addition of new strings.
StringDeclaration.h #import <Foundation/Foundation.h> @interface StringDeclaration : NSObject extern NSString *const cellIdentifier,*const name,*const designation,*const salary,*const companyName,*const empBelongsToCompany; @end StringDeclaration.m #import "StringDeclaration.h" @implementation StringDeclaration NSString * const cellIdentifier=@"cell",*const name=@"employee_Name",*const designation=@"employee_Designation",*const salary=@"employee_Salary",*const companyName=@"company_Name",*const empBelongsToCompany=@"belongsToCompany"; @end
New file for addition of new company will be done with the file named as AddCompanyViewController.
AddCompanyViewController.h #import <UIKit/UIKit.h> #import "Company.h" #import <CoreData/CoreData.h> #import "StringDeclaration.h" @interface AddCompanyViewController : UIViewController - (IBAction)btnSaveCompany:(id)sender; @property (strong) NSManagedObject *device; @property (weak, nonatomic) IBOutlet UITextField *txtCompanyName; - (IBAction)btnBack:(id)sender; @end AddCompanyViewController.m #import "AddCompanyViewController.h" @interface AddCompanyViewController () @property (strong) NSMutableArray *devices; @end @implementation AddCompanyViewController - (NSManagedObjectContext *)managedObjectContext { NSManagedObjectContext *context = nil; id delegate = [[UIApplication sharedApplication] delegate]; if ([delegate performSelector:@selector(managedObjectContext)]) { context = [delegate managedObjectContext]; } return context; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (IBAction)btnSaveCompany:(id)sender { NSManagedObjectContext *context = [self managedObjectContext]; Company *newDevice = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Company class]) inManagedObjectContext:context]; newDevice.company_Name=self.txtCompanyName.text; NSError *error = nil; // Save the object to persistent store if (![context save:&error]) { NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]); } [self dismissViewControllerAnimated:YES completion:nil]; } - (IBAction)btnBack:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; } @end
AddEmployeeDetailViewController file includes one more textfield which provides picker on click. Picker includes the list of company where employee can be added.
AddEmployeeDetailViewController.h #import <UIKit/UIKit.h> #import <CoreData/CoreData.h> #import "Employee.h" @interface AddEmployeeDetailViewController : UIViewController<UIPickerViewDataSource,UIPickerViewDelegate> { UIPickerView *picker; UIButton *done; } @property (weak, nonatomic) IBOutlet UITextField *txtEmployeeName; @property (weak, nonatomic) IBOutlet UITextField *txtEmployeeDesignation; @property (weak, nonatomic) IBOutlet UITextField *txtEmployeeSalary; - (IBAction)btnSave:(id)sender; - (IBAction)btnCancel:(id)sender; @property (weak, nonatomic) IBOutlet UITextField *txtCompany; @property (strong) NSManagedObject *employeeObject; @property (strong, nonatomic)NSArray *dataSourceArray; @end AddEmployeeDetailViewController.m #import "AddEmployeeDetailViewController.h" #import "StringDeclaration.h" #import "Company.h" @interface AddEmployeeDetailViewController (){ Company *selectedCompany; } @property (strong) NSMutableArray *companyArray; @end @implementation AddEmployeeDetailViewController - (NSManagedObjectContext *)managedObjectContext { NSManagedObjectContext *context = nil; id delegate = [[UIApplication sharedApplication] delegate]; if ([delegate performSelector:@selector(managedObjectContext)]) { context = [delegate managedObjectContext]; } return context; } - (void)viewDidLoad { [super viewDidLoad]; if (self.employeeObject) { [self.txtEmployeeName setText:[self.employeeObject valueForKey:name]]; [self.txtEmployeeDesignation setText:[self.employeeObject valueForKey:designation]]; [self.txtEmployeeSalary setText:[self.employeeObject valueForKey:salary]]; } } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self data]; // Fetch the devices from persistent data store } -(void)data { NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Company"]; self.companyArray = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy]; NSLog(@"%@",self.companyArray); picker = [[UIPickerView alloc] init]; [done setTitle:@"Done" forState:UIControlStateNormal]; picker.dataSource = self; picker.delegate = self; [_txtCompany setInputView:picker]; _dataSourceArray = [self.companyArray valueForKey:companyName]; UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; toolBar.barStyle = UIBarStyleBlackOpaque; UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneTouched:)]; [toolBar setItems:[NSArray arrayWithObjects:doneButton, nil]]; _txtCompany.inputAccessoryView = toolBar; // include list of company } - (void)doneTouched:(UIBarButtonItem *)sender { [_txtCompany resignFirstResponder]; // hide the picker view } // Do any additional setup after loading the view. - (NSInteger)numberOfComponentsInPickerView: (UIPickerView *)pickerView { return 1; } - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { return self.companyArray.count; //returns no of rows } - (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { Company *company = self.companyArray[row]; return company.company_Name; } -(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { Company *company = self.companyArray[row]; selectedCompany = company; _txtCompany.text = company.company_Name; if(_txtCompany.text>0) { } else { [_txtCompany setInputView:picker]; } } - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField { return YES; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (IBAction)btnSave:(id)sender { NSManagedObjectContext *context = [self managedObjectContext]; if (self.employeeObject) { // Update existing device [self.employeeObject setValue:self.txtEmployeeName.text forKey:name]; [self.employeeObject setValue:self.txtEmployeeDesignation.text forKey:designation]; [self.employeeObject setValue:self.txtEmployeeSalary.text forKey:salary]; [self.employeeObject setValue:selectedCompany forKey:empBelongsToCompany]; } else { // Create a new device Employee *newDevice = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([Employee class]) inManagedObjectContext:context]; newDevice.employee_Name=self.txtEmployeeName.text; newDevice.employee_Designation=self.txtEmployeeDesignation.text; newDevice.employee_Salary=self.txtEmployeeSalary.text; newDevice.belongsToCompany=selectedCompany; NSError *error = nil; // Save the object to persistent store if (![context save:&error]) { NSLog(@"Can't Save! %@ %@", error, [error localizedDescription]); } } [self dismissViewControllerAnimated:YES completion:nil]; } - (IBAction)btnCancel:(id)sender { [self dismissViewControllerAnimated:YES completion:nil]; } @end
Now in the controller which display the list of employees can fetch the company name also which is saved in another entity named as Company. We are able to access the value from another entity because of relationship between the two entities otherwise it is not possible. So below is the code which will help in accessing the data store in another entity.EmployeeListViewController.h #import <UIKit/UIKit.h> @interface EmployeeViewController : UIViewController - (IBAction)btnAddEmployee:(id)sender; @property (weak, nonatomic) IBOutlet UITableView *tblView; - (IBAction)addCompany:(id)sender; @end EmployeeListViewController.m #import "EmployeeViewController.h" #import <CoreData/CoreData.h> #import "AddEmployeeDetailViewController.h" #import "StringDeclaration.h" #import "AddCompanyViewController.h" @interface EmployeeViewController () @property (strong) NSMutableArray *employeeArray; @end @implementation EmployeeViewController - (NSManagedObjectContext *)managedObjectContext { NSManagedObjectContext *context = nil; id delegate = [[UIApplication sharedApplication] delegate]; if ([delegate performSelector:@selector(managedObjectContext)]) { context = [delegate managedObjectContext]; } return context; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; [self data]; [self.tblView reloadData]; // Fetch the devices from persistent data store } -(void)data { NSManagedObjectContext *managedObjectContext = [self managedObjectContext]; NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Employee"]; self.employeeArray = [[managedObjectContext executeFetchRequest:fetchRequest error:nil] mutableCopy]; } -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { // Return the number of sections. return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { // Return the number of rows in the section. return self.employeeArray.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath]; // Configure the cell... NSManagedObject *employee = [self.employeeArray objectAtIndex:indexPath.row]; Company *company=[employee valueForKey:empBelongsToCompany]; [cell.textLabel setText:[NSString stringWithFormat:@"%@ %@ %@", [employee valueForKey:name], [employee valueForKey:designation],company.company_Name]];//fetch the data from other entity(table) [cell.detailTextLabel setText:[employee valueForKey:salary]]; return cell; } - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { // Return NO if you do not want the specified item to be editable. return YES; } - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { NSManagedObjectContext *context = [self managedObjectContext]; if (editingStyle == UITableViewCellEditingStyleDelete) { // Delete object from database [context deleteObject:[self.employeeArray objectAtIndex:indexPath.row]]; NSError *error = nil; if (![context save:&error]) { NSLog(@"Can't Delete! %@ %@", error, [error localizedDescription]); return; } // Remove device from table view [self.employeeArray removeObjectAtIndex:indexPath.row]; [self.tblView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; } } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([[segue identifier] isEqualToString:@"Update"]) { NSManagedObject *selectedDevice = [self.employeeArray objectAtIndex:[[self.tblView indexPathForSelectedRow] row]]; AddEmployeeDetailViewController *destViewController = segue.destinationViewController; destViewController.employeeObject = selectedDevice; } } - (IBAction)btnAddEmployee:(id)sender { UIStoryboard* sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; AddEmployeeDetailViewController* vc1 = [sb instantiateViewControllerWithIdentifier:NSStringFromClass([AddEmployeeDetailViewController class])]; [vc1 setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal]; [self presentViewController:vc1 animated:YES completion:nil]; } - (IBAction)addCompany:(id)sender { UIStoryboard* sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; AddCompanyViewController* vc1 = [sb instantiateViewControllerWithIdentifier:NSStringFromClass([AddCompanyViewController class])]; [vc1 setModalTransitionStyle:UIModalTransitionStyleFlipHorizontal]; [self presentViewController:vc1 animated:YES completion:nil]; } @end
Output:-You can download the project from the given link. You need Xcode 7.2 to build the project.
0 Comment(s)