IOS 5 | iPhone | iPad | Tutorial on Developing Core Data Applications for Beginners
By klanguedoc
This tutorial will show you how to create a Core Data application for IOS 5 devices. Core Data offers a higher level of abstraction to data persistence than SQLite. In fact Core Data uses SQLite for the actual storage among other storage types, however Core Data is much more than just storage. Core Data provides the tools to design your data model for your app, akin to having an E/R tool. Core Data is the most widely used storage facility with Apple apps -- for both OSX and IOS.
This tutorial will walk you through the steps to create an IOS 5 app that uses Core Data for data persistence. The tutorial will also show you how to setup input screens and output screens to input new data and to display the stored data.
Before starting the tutorial proper, clarification on a couple of concepts will help your understanding and help your gasp the logic in the tutorial starting with the Basic Architecture
Basic Architecture
Core Data is organized into NSManagedObjects which corresponds to tables in a SQLite database or other data persistence types. These NSManagedObjects can be broken down into Entities, which can be associated with table in a database. Entities can have Attributes which loosely translates as columns. NSManagedObjects are origanized into a NSManagedObjectModel, which can have several Entities with Relationships. Finally a “Select” can be performed using a NSFetchedManagedObject using Predicates.
That was the very skinny. I will provide some code samples for each of these concepts
NSFetchedManagedObject
You retrieve NSManagedObjects using a NSFetchedManagedObject. You can display or work with a subset of the data that is in the store using a Predicate just like a regular query.
Here are the basic steps for using the NSFetchedManagedObject to retrieve data from the store.
- Initialize a NSManagedObjectContext
- Initialize a NSEntityDescription
- Create a NSFetchedRequest
- Add a predicate and or a sort order (optional)
- Execute the request
NSManagedObjectContext
Tne NSManagedObjectContext is the open session with the persistence store. You create and initialize a NSManagedObjectContext before creating, updating, deleting NSManagedObjects and fetching records.
NSManagedObjectModel
The NSManagedObjectModel defines the Entities, Attributes, Relationships and Predicates. A NSManagedObjectModel is encapsulated in the xcdatamodelid file. In essence the NSManagedObjectModel is the schema for the application you will create or are creating.
NSManagedObject
NSManagedObjects represents Entities in the NSManagedObjectModel which in turn represent tables in a database like SQLite. These objects can act as a dictionary having a many attributes (columns) with most standard data types including blobs.
Entities
Entities are defined in the NSManagedObjectModel. You can think of them as tables in a database and other supported store types in Core Data. Each Entity has a name and a class that is defined at runtime or can be defined from the schema model as NSManagedObjects throught the XCode Edtor command: Create NSManagedObject Subclass...
Attributes
Attributes define the dimensions in an Entity. They have a data type that matches most standard data types, especially those supported by SQLite database, which is the most used persistence store used with Core Data. Attributes are the Entities properties along with Relationships.
Relationships
As mentioned Relationships define the relationship between Entities. Relationships support “to-one” and “to-many” relationships with Entities. Relationships can be optional and you can also configure any “delete” rules that may apply.
Predicates
Predicates can be akin to a select statement in a SQL query. You can define them either through the NSManagedObjectModel Schema designer or through Objective-C . Predicates have a special syntax and can be dynamic by using variables to define the predicate.
Templates for Core Data in IOS 5
The IOS 5 SDK provides two templates for creating Data Core applications. However this doesn’t limit you from choosing another template - it just means that you will need to write a lot more code and configuration if you don’t use the offered templates.
Utility Application
This template offers an application starting point with a main view and an alternate view. It offers the possibility to include Core Data functionality and will generate all the code and configuration to get you started.
Master-Detail View Application
This type of application generates a navigation view controller and detail view with an UITableView controller which can display data from a Core Data persistence store.
Tutorial
This is a quick tutorial to demonstrate how easy it is to use Core Data to capture data from an application.
Step 1 : Create Project
For this tutorial I will use the Utility application template. Leave the Core Data enabled. Name your project anything you like.
Step 2 : Create Core Data Schema
Once the project is created, you will notice that a file with the extension “xcdatamodeId” was created. This is the schema file where you will define your Entities, Attributes, Relationships and Predicates. Select it now.
Select the Entity node and click on the “Add Entity” button towards the bottom of the screen. For this tutorial I will create two Entities: Continent and Country. Note the Entity names must start a Capital letter. Next select each Entity in turn and either click on the “+” below the Attribute section or click on the “Add Attribute” button on the bottom of the screen. For each Entity add one Attribute “name” with a string data type
Finally add a relationship by selecting each Entity in turn. For the Continent, name the relationship “continents” and the destination should be the “Country” Entity. The inverse will be created once the “countries” relationship is created under Country.
We will use the default Predicate of “All” which is the default.
Step 3 : Create Input Screen
Next open the storyboard file and add two labels and two text fields and a button. Layout the screen as in the following screenshot. With the storyboard file open, click on the Assistant Editor to open the corresponding header file. Create IBOutlets for each field by holding down the “control” button dragging a connection line using the left mouse button from each field to the header file. In the corresponding popup, make sure the connection type is IBOutlet and enter a name for the connection like continentNameFld. Click on the “connect” button to add the code and create a connection. Repeat the process for the second field which can be named something like countryNameFld.
For the button, repeat the process, but change the connection type to “IBAction” and name it something like saveData.
Step 4 : Add Input Logic
To cap off this tutorial, we will add some code to the saveData method (or whatever) you named yours. Locate the method in the implementation file. Add the following code:
- (IBAction)saveData:(id)sender {
NSManagedObjectContext *cxt = [self managedObjectContext];
NSManagedObject *newContinent = [NSEntityDescription insertNewObjectForEntityForName:@"Continent" inManagedObjectContext:cxt];
[newContinent setValue:self.continentNameFld.text forKey:@"name"];
_continentNameFld.text = @"";
NSManagedObject *newCountry = [NSEntityDescription insertNewObjectForEntityForName:@"Country" inManagedObjectContext:cxt];
[newCountry setValue:self.countryNameFld.text forKey:@"name"];
_countryNameFld.text = @"";
NSError *err;
if (![cxt save:&err]) {
NSLog(@"An error has occured: %@", [err localizedDescription]);
}
}
As you can see the first line creates a NSManagedObjectContext as explained earlier. Next we create a new NSManagedObject for the Continent and Country Entities using the InsertNewObjectForEntityForName method of the NSManagedObject class.
Next we set the value which we get from each field in the ViewController using the setValue method and the forKey method. Finally we save the changes by calling the save method from our context object. If we are unable to save, we raise an error.
Step 5 : Test App
Click on the run button to launch the IOS 5 Simulator. Try entering a continent and country in the corresponding fields and click on the save button. Watch the log to see if any errors are raised as you step through the saveData method. If no errors were raised, the data was successfully saved to the database.
In Summary
Working with Core Data is very easy if you use a pre defined template. It is a bit more trickier if you build a Core Data app from scratch.
kcbAppDelegate.h
// // kcbAppDelegate.h // TestCoreData // // Created by Kevin Languedoc on 1/8/12. // Copyright (c) 2012 kCodebook. All rights reserved. // #import <UIKit/UIKit.h> @interface kcbAppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; - (void)saveContext; - (NSURL *)applicationDocumentsDirectory; @end
kcbAppDelegate.m
//
// kcbAppDelegate.m
// TestCoreData
//
// Created by Kevin Languedoc on 1/8/12.
// Copyright (c) 2012 kCodebook. All rights reserved.
//
#import "kcbAppDelegate.h"
#import "kcbMainViewController.h"
@implementation kcbAppDelegate
@synthesize window = _window;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
kcbMainViewController *controller = (kcbMainViewController *)self.window.rootViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"TestCoreData" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"TestCoreData.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end|
|
5000mAh Universal Portable External Battery Charger Power Bank For IPhone Ipad
Current Bid: $17.80
|
|
|
Black Unisex Touch Screen Winter Gloves for iPhone/iPad/HTC/Smart Phone UK
Current Bid: $3.12
|
|
|
Black Unisex Touch Screen Winter Gloves for iPhone/iPad/HTC/Smart Phone UK
Current Bid: $3.12
|
|
|
10x Anti Dust Plug Opener SIM Card Tray For Apple iPad 2 3 iPod iPhone 3GS 4G 4S
Current Bid: $2.88
|
|
|
New Real Madrid Home button Sticker for iPhone 4 4S 3GS IPAD IPOD C
Current Bid: $1.35
|
kcbMainViewController.h
// // kcbMainViewController.h // TestCoreData // // Created by Kevin Languedoc on 1/8/12. // Copyright (c) 2012 kCodebook. All rights reserved. // #import "kcbFlipsideViewController.h" #import <CoreData/CoreData.h> @interface kcbMainViewController : UIViewController <kcbFlipsideViewControllerDelegate> @property (strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (weak, nonatomic) IBOutlet UITextField *continentNameFld; @property (weak, nonatomic) IBOutlet UITextField *countryNameFld; - (IBAction)saveData:(id)sender; @end
kcbMainViewController.m
//
// kcbMainViewController.m
// TestCoreData
//
// Created by Kevin Languedoc on 1/8/12.
// Copyright (c) 2012 kCodebook. All rights reserved.
//
#import "kcbMainViewController.h"
@implementation kcbMainViewController
@synthesize managedObjectContext = _managedObjectContext;
@synthesize continentNameFld = _continentNameFld;
@synthesize countryNameFld = _countryNameFld;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setContinentNameFld:nil];
[self setCountryNameFld:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark - Flipside View
- (void)flipsideViewControllerDidFinish:(kcbFlipsideViewController *)controller
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@"listView"]) {
[[segue destinationViewController] setDelegate:self];
}
}
- (IBAction)saveData:(id)sender {
NSManagedObjectContext *cxt = [self managedObjectContext];
NSManagedObject *newContinent = [NSEntityDescription insertNewObjectForEntityForName:@"Continent" inManagedObjectContext:cxt];
[newContinent setValue:self.continentNameFld.text forKey:@"name"];
_continentNameFld.text = @"";
NSManagedObject *newCountry = [NSEntityDescription insertNewObjectForEntityForName:@"Country" inManagedObjectContext:cxt];
[newCountry setValue:self.countryNameFld.text forKey:@"name"];
_countryNameFld.text = @"";
NSError *err;
if (![cxt save:&err]) {
NSLog(@"An error has occured: %@", [err localizedDescription]);
}
}
@endComments
I would store my initial Parsed data from JSON into a NSMutableArray, then loop through the array to populate entities using code from above. "Seeding" Core Data is always an issue. I hope this helps.
I've read in the iOS5 Developer's Cookbook you could render Core Data in a UITableView, but haven't quite figured out that recipe yet.
Hi,
I have followed your tutorial and it is really easy to understand:-)
I keep getting an error though, I have even copied and paster your code to see what I have done different.
It says:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Cannot create an NSPersistentStoreCoordinator with a nil model'
Anything I have done wrong?? I know I have, but maybe its something simple:-)
Cheers Jeff
Please check the AppDelegate file to make sure that the NSPersistentStoreCoordinator is created and initialized
Hi again,
Yes it is definitely initialized - and it appears as often in my code as it does in yours.
Could it be because I remade my .xcdatamodeld file? Liek I deleted the original one and remade it so I could practice:-)
Jeff
Yes, you could be missing the required methods in the AppDelegate:
Here is a sample AppDelegate file for CoreData:
@implementation klAppDelegate
@synthesize window = _window;
@synthesize managedObjectContext = __managedObjectContext;
@synthesize managedObjectModel = __managedObjectModel;
@synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
klMainViewController *controller = (klMainViewController *)self.window.rootViewController;
controller.managedObjectContext = self.managedObjectContext;
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
/*
Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application
{
// Saves changes in the application's managed object context before the application terminates.
[self saveContext];
}
- (void)saveContext
{
NSError *error = nil;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil)
{
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
}
}
#pragma mark - Core Data stack
/**
Returns the managed object context for the application.
If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
*/
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] init];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
/**
Returns the managed object model for the application.
If the model doesn't already exist, it is created from the application's model.
*/
- (NSManagedObjectModel *)managedObjectModel
{
if (__managedObjectModel != nil)
{
return __managedObjectModel;
}
NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataCountries" withExtension:@"momd"];
__managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return __managedObjectModel;
}
/**
Returns the persistent store coordinator for the application.
If the coordinator doesn't already exist, it is created and the application's store added to it.
*/
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
if (__persistentStoreCoordinator != nil)
{
return __persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataCountries.sqlite"];
NSError *error = nil;
__persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
{
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return __persistentStoreCoordinator;
}
#pragma mark - Application's Documents directory
/**
Returns the URL to the application's Documents directory.
*/
- (NSURL *)applicationDocumentsDirectory
{
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}
@end
Cool - got it fixed, what the issue was that the line that contains : @"CoreDataExercisde" withExtension:@"momd"]; was set to @"TestCoreData withExtension:@"momd"]; once I changed that it was fine:-)
Thank you - great tutorial:-)
Super, well I am happy that you got worked out. There is nothing more frustrating then staring at code and not knowing where the problem is. Thanks for your kind feedback, I really appreciate it.
For some reason, you comments are not showing up in my notifications. I am deeply sorry because I strive to answer every comments. I have read part of the book. It has good examples. For Core Data, I strongly suggest using one of the templates in Xcode to get started.
Just one more quick question - are you planning or do you already have a tutorial on how to display the result of this exercise in a UITableView?
Cheers Jeff
@Jeffwk: To render Core Data in a table view, I've followed: http://timroadley.com/2012/02/09/core-data-basics-
Hi Jeff,
Actually I am working on one. the code is complete, I just need to write up the instructions. I will finish this week. Thanks for the link. I am glad you were able to push through.
K
ilhan 3 months ago
Firstly thanks for this nice tutorial. I have a navigation based application and i need to save JSON data to Core Data Model than retrieve data from there. Can you give me an idea about how to do that? I can parse the response of GET(mean i parse JSON) but can't add into Entities. Thanks