Technical eBook for iOS Developers

  • 377 views
Uploaded on

 

More in: Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
377
On Slideshare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
0
Comments
0
Likes
2

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1.    1Build Your First AppWith Core DataA Step by Step GuideUPDATEDfor StackMobiOS SDK v1.2.0
  • 2.    2What is Core Data?If you want to build anything beyond the most simplistic apps foriOS, you’ll need a way to persist data. Luckily, Apple provides theCore Data framework, a persistence layer that efficiently handlesthe coordination of saving/updating/deleting data, as well asmaintaining data integrity.With Core Data, you define the schema you want your data toconform to, and afterwards create objects from that schema toperform CRUD operations on. You don’t have to worry about what’sgoing on at the actual database level, as this is all abstracted away.Here at StackMob, we’ve placed an emphasis on the use of CoreData in our iOS SDK. If you’re new to Core Data, have no fear!This tutorial will get you started on the basics.Part 1:Learning Core DataIt’s worth noting that Core Data is not itself a database. By default, it sits on top of SQLite3, a lightweightdatabase baked into iOS. However, it can be configured to persist data to a document file or, in the caseof the StackMob SDK, a URL service that persists the data elsewhere.Why Should I Learn Core Data?Before Core Data, developers had to work directly with SQLite3 to save their data. This provided manyheadaches; you had to write verbose SQL commands and handle the logic for CRUD operations. Youwere also responsible for insuring the data you saved matched your schema. By the end of it all, you hadin essence written your own persistence layer! Core Data handles all the heavy lifting for you. As youpersist your data all logic is managed under the hood with optimal performance in mind.Core Data has a little bit of a learning curve, which can dissuade developers who want to dive straightinto building to use it. However, taking the time to gain an understanding of the Core Data fundamentalswill pay large dividends in the long run, as it is a powerful tool that will enable you to build robust anddata-driven apps.
  • 3.    3We’ll name our project “MusicLabel” and name the class prefix “MLBL”.Make sure you have “Use Core Data” selected. Doing so ensures theproject generates the configurations and boilerplate code necessaryto get started with Core Data. Uncheck “Include Unit Tests” since wewon’t be testing our application.Lets build that out in a project:Fire up Xcode and create a new project. Choose “Empty Application”and click “Next”.Lets Get StartedThe NSManagedObjectModel iswhere you define your schemafor Core Data. In your model,you define the Entities, or classesof data in your schema. Withinyour Entities, you set theirAttributes, which are the details of your data. Finally, youcan link Entities together through Relationships.For example, you could create a model with an entityLabel that defines a music label, an entity Artistrepresenting artists who are part of the label, and anentity Album representing albums recorded by artists. Each entitywould have attributes representing details; all three entities wouldbe connected through relationships.
  • 4.    4For now lets concentrate onthe data model. Select the“MusicLabel.xcdatamodeld” file,and make sure the editor style isset to table.Add the following attributesand corresponding types to the“Label” entity:Add another entity, “Artist”, andadd the following attributes:Add one more entity, “Album”,and add the following attributes:foundedgenrenamehometowntitlereleasedDateStringStringStringStringDateAttributeAttributeAttributeTypeTypeTypeClick on “Add Entity” at thebottom of the Xcode window andname it “Label”. With the entityselected, click “Add Attribute”.We’ll call this attribute “name”,and set its type to “String”.Switch the Editor Style to graph in the bottom right corner of the Xcode window.
  • 5.    5With the “Label” entity selected, click and hold “Add Attribute” until you see the option “Add Relationship”.Select Add Relationship. Give it the name “artists”and set the destination to the “Artist” entity. Byestablishing this relationship, we’re effectivelysaying “every Label has an Artist”. Our label can havemore than one artist, so we’ll make the relationshipa “To-Many Relationship”. Also, set the delete ruleto “Cascade”; this ensures that when an object isdeleted, its child objects will be deleted as well.Now we’ll want to make an inverse relationship back to the parent.Select the “Artist” entity and click “Add Relationship”. Name therelationship “label” and set the destination to the “Label” entity.Set the inverse to the “artists” relationship.
  • 6.    6“Label” to “Artist”“Artist” to “Label”“Artist” to “Album”“Album” to “Artist”artistslabelalbumsartistTo-manyOne-to-oneTo-ManyOne-to-oneCascadeNullifyCascadeNullifyRelationship Name Type Delete RuleWhen you’re finished, your model should look like this:Use these same steps to set relationships between the “Artist” and “Album” entities. Make a relationshipfrom the “Artist” entity to the “Album” entity titled “albums”. Make it a “To-Many Relationship” and setthe delete rule to “Cascade”. Make a relationship from the “Album” entity to the “Artist” entity with thename “artist” and make the inverse be the the “albums” relationship.Use this table for reference:
  • 7.    7Finally, select the “Label” entity, and click File > New > File.Choose the “NSManagedObject subclass” template.This generates Objective-C class files for the “Label” entity; you should see a “Label.h” file as well as a“Label.m” file. Use the same steps to generate class files for the “Artist” and “Album” entities (make sureto do it in the order Label > Artist > Album). With class files generated for each of the entities, our setupis complete.What’s Next?So far, we’ve learned the basics of how Core Data works. We covered a high-level overview of the subject and created an Xcode project with our ownNSManagedObjectModel. In part 2 of our tutorial we’ll take a more detailed look atCore Data and implement CRUD operations.
  • 8.    8In this part of the tutorial we’ll delve a little deeper into Core Data,and perform basic CRUD operations. If you’re not familiar with theterm, CRUD stands for Create, Read, Update and Delete; these arethe four fundamental operations performed on a database.Part 2:Diving into CRUDNSManagedObjectContext & NSPersistentStoreCoordinatorThe NSManagedObjectModel is only 1/3 of the Core Data picture. Let’s introduce theNSManagedObjectContext. You can think of NSManagedObjectContext as a “scratch pad” where allthe changes happen. Here you create, read, update and delete objects from your database. None ofthe changes you make are actually persisted until you call the “save” method on your managed objectcontext instance.So when a call to save is made,what happens next? Sittingbetween the managed objectcontext and the database is theNSPersistentStoreCoordinator.The coordinator acts as aninterface to the database whereyour data is being persisted. Thepersistent store coordinatorgrabs any objects that will besaved from the managed objectcontext and verifies that namesand types are consistent with themanaged object model. It thensends the objects on their way tobe persisted to the database.
  • 9.    9Creating an objectOpen the “MLBLAppDelegate.m” file. In it, you’ll see methods to setup the context, model and persistentstore coordinator. Import the “Label.h”, “Artist.h”, and “Album.h” files. Add the following method:- (void) create {// Grab the contextNSManagedObjectContext *context = [self managedObjectContext];// Grab the Label entityLabel *label = [NSEntityDescription insertNewObjectForEntityForName:@”Label” inManagedObjectCon text:context];// Set label namelabel.name = @”Diplomat Records”;// Create a DateNSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];[dateFormatter setDateFormat:@”YYYY”];NSDate *dateFounded = [dateFormatter dateFromString:@”2003”];// Set the year founded for the labellabel.founded = dateFounded;// Set the label genrelabel.genre = @”Rap/Hip-hop”;// Insert the Artist entityArtist *artist = [NSEntityDescription insertNewObjectForEntityForName:@”Artist”inManagedObjectContext:context];// Set the artist attributesartist.name = @”Cam’Ron”;artist.hometown = @”Harlem, NY”;// Insert Album entityAlbum *album = [NSEntityDescription insertNewObjectForEntityForName:@”Album”inManagedObjectContext:context];// Set album attributesalbum.title = @”Come Home With Me”;NSDate *releaseDate = [dateFormatter dateFromString:@”2002”];album.released = releaseDate;// Set relationships[label addArtistsObject:artist];[artist setLabel:label];[artist addAlbumsObject:album];[album setArtist:artist];// Save everythingNSError *error = nil;if ([context save:&error]) {NSLog(@”The save was successful!”);} else {NSLog(@”The save wasn’t successful: %@”, [error userInfo]);}}Get the Code from GitHub
  • 10.    10Make sure to call [self create] in the application:didFinishLaunchingWithOptions: method. Build yourproject and run it. Check the output in the log navigator to see if it saved properly. You should see this output:It worked? Great, now let’s walkthrough reading data.Reading an objectWith Core Data, you perform“fetch requests” to access savedobjects. These objects arealways returned as instances ofNSManagedObject. Check outNSFetchRequest for more info.Add the following method to the“MLBLAppDelegate.m” file:- (void) read {NSManagedObjectContext *context = [self managedObjectContext];// Construct a fetch requestNSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];NSEntityDescription *entity = [NSEntityDescription entityForName:@”Label”inManagedObjectContext:context];[fetchRequest setEntity:entity];NSError *error = nil;NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];for (Label *label in fetchedObjects) {// Log the label detailsNSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];[dateFormatter setDateFormat:@”YYYY”];NSLog(@”%@, est. %@ (%@)”, label.name, [dateFormatter stringFromDate:label.founded], label.genre);NSLog(@”tArtists:”);NSSet *artists = label.artists;for (Artist *artist in artists) {// Log the artist detailsNSLog(@”tt%@ (%@)”, artist.name, artist.hometown);NSLog(@”tttAlbums:”);NSSet *albums = artist.albums;for (Album *album in albums) {// Log the album detailsNSLog(@”tttt%@ (%@)”, album.title, [dateFormatter stringFromDate:album.re-leased]);}}}}Get the Code from GitHub
  • 11.    11Replace [self create] with [self read] in the application:didFinishLaunchingWithOptions: method. Buildand run, and voila! A printout of the objects should appear in the log navigator.- (void) update {// Grab the contextNSManagedObjectContext *context = [self managedObjectContext];// Perform fetch requestNSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];NSEntityDescription *entity = [NSEntityDescription entityForName:@”Label”inManagedObjectContext:context];[fetchRequest setEntity:entity];NSError *error = nil;NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];// Date formatter comes in handyNSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];[dateFormatter setDateFormat:@”YYYY”];// Grab the labelLabel *label = [fetchedObjects objectAtIndex:0];// Juelz SantanaArtist *juelz = [NSEntityDescription insertNewObjectForEntityForName:@”Artist” inManagedObject-Context:context];juelz.name = @”Juelz Santana”;juelz.hometown = @”Harlem, NY”;// Juelz Santana albumsAlbum *juelzAlbum = [NSEntityDescription insertNewObjectForEntityForName:@”Album” inManagedOb-jectContext:context];juelzAlbum.title = @”From Me to U”;juelzAlbum.released = [dateFormatter dateFromString:@”2003”];[juelzAlbum setArtist:juelz];Album *juelzAlbum2 = [NSEntityDescription insertNewObjectForEntityForName:@”Album” inManagedOb-jectContext:context];juelzAlbum2.title = @”What The Game’s Been Missing!”;juelzAlbum2.released = [dateFormatter dateFromString:@”2005”];[juelzAlbum2 setArtist:juelz];// Set relationships[juelz addAlbums:[NSSet setWithObjects:juelzAlbum, juelzAlbum2, nil]];// Jim JonesArtist *jimmy = [NSEntityDescription insertNewObjectForEntityForName:@”Artist” inManagedObject-Context:context];jimmy.name = @”Jim Jones”;jimmy.hometown = @”Harlem, NY”;// Jim Jones albumsAlbum *jimmyAlbum = [NSEntityDescription insertNewObjectForEntityForName:@”Album” inManagedOb-jectContext:context];jimmyAlbum.title = @”On My Way to Church”;jimmyAlbum.released = [dateFormatter dateFromString:@”2004”];Updating an objectLet’s update our label and add a few more artists and albums. Add this method:
  • 12.    12[jimmyAlbum setArtist:jimmy];Album *jimmyAlbum2 = [NSEntityDescription insertNewObjectForEntityForName:@”Album” inManagedOb-jectContext:context];jimmyAlbum2.title = @”Harlem: Diary of a Summer”;jimmyAlbum2.released = [dateFormatter dateFromString:@”2005”];[jimmyAlbum2 setArtist:jimmy];Album *jimmyAlbum3 = [NSEntityDescription insertNewObjectForEntityForName:@”Album” inManagedOb-jectContext:context];jimmyAlbum3.title = @”Hustler’s P.O.M.E. (Product of My Environment)”;jimmyAlbum3.released = [dateFormatter dateFromString:@”2006”];[jimmyAlbum3 setArtist:jimmy];// Set relationships[jimmy addAlbums:[NSSet setWithObjects:jimmyAlbum, jimmyAlbum2, jimmyAlbum3, nil]];// Freekey ZekeyArtist *freekey = [NSEntityDescription insertNewObjectForEntityForName:@”Artist” inManagedOb-jectContext:context];freekey.name = @”Freekey Zekey”;freekey.hometown = @”Harlem, NY”;Album *freekeyAlbum = [NSEntityDescription insertNewObjectForEntityForName:@”Album” inManaged-ObjectContext:context];freekeyAlbum.title = @”Book of Ezekiel”;freekeyAlbum.released = [dateFormatter dateFromString:@”2007”];[freekeyAlbum setArtist:freekey];[freekey addAlbumsObject:freekeyAlbum];// Set relationships[label addArtists:[NSSet setWithObjects:juelz, jimmy, freekey, nil]];// Save everythingif ([context save:&error]) {NSLog(@”The save was successful!”);} else {NSLog(@”The save wasn’t successful: %@”, [error localizedDescription]);}}Replace [self read] with [self update] in the application:didFinishLaunchingWithOptions: method. Buildand run, and check the log navigator for a successful save. Now let’s print them to the log again. Replace[self update] with [self read]. Build and run, and you should see all the artists/albums under the label.Run it a few more times and compare the log output each time. The order will vary almost every time.Fetch requests return objects unordered, unless specified otherwise. To do so, you need to use NSSort-Descriptor to organize your results. Use NSPredicate to grab specific objects.Get the Code from GitHub
  • 13.    13Add the line [self delete] right before [self read] in the application:didFinishLaunchingWithOptions:method. Build and run, and you should see Freekey Zekey disappear from the results. His album shouldbe gone too, as we set the delete rule for that relationship to “Cascade”.What’s Next?Now that you’ve learned the basics of Core Data, it’s time to start building a full-fledgedapplication on top of it. In part 3 of our tutorial, we’ll add a UI to what we’ve built so far.Download the source code for this tutorial.Deleting an objectFinally, we’ll delete an object. Let’s add this method:- (void) delete {// Grab the contextNSManagedObjectContext *context = [self managedObjectContext];// We’re looking to grab an artistNSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];NSEntityDescription *entity = [NSEntityDescription entityForName:@”Artist”inManagedObjectContext:context];[fetchRequest setEntity:entity];// We specify that we only want Freekey ZekeyNSPredicate *predicate = [NSPredicate predicateWithFormat:@”name == %@”, @”Freekey Zekey”];[fetchRequest setPredicate:predicate];NSError *error = nil;NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];// Grab the artist and deleteArtist *freekey = [fetchedObjects objectAtIndex:0];[freekey.label removeArtistsObject:freekey];// Save everythingif ([context save:&error]) {NSLog(@”The save was successful!”);} else {NSLog(@”The save wasn’t successful: %@”, [error localizedDescription]);}}Get the Code from GitHub
  • 14.    14Part 3:Adding the User InterfaceIn this section, we’ll focus on the UI, or user interface, the layeron top of our view controllers that allows a user to interact withour data.The setup of the UI is equally as important as Core Data. An app that functions perfectly won’t besuccessful if its interface is not intuitive and aesthetically pleasing. Before touchscreen devices becameubiquitous, the UI was sometimes cast as an afterthought. Now it’s virtually impossible to ignore.Tablets and phones come with constraints in screen size, requiring much more consideration for the userexperience and flow of information through an app. Great UI design properly communicates to the userthe purpose of your application.With that in mind, we’ll construct a simple user interface for our MusicLabel app, which will allow usersto create and delete entries into the database.Create a storyboardFirst, we’ll need to add astoryboard to our project. Presscommand + N and select “UserInterface” from the availabletemplates. Choose Storyboard,and click next.
  • 15.    15Name the file “MainStoryboard”and click create. In theMusicLabel project, target selectthe storyboard we just createdto be the Main Storyboard.Create a tableviewClick on the storyboard and makesure the “Utilities” pane is open.Drag a table view controllerfrom the object library onto thestoryboard.
  • 16.    16With the prototype cell selected, navigate to the attributes inspector. Enter “Cell” as an identifier.Press command + N, and from the“Cocoa touch” templates, select“Objective-C class”.Name the file“MLBLLabelViewController”and make it a subclass ofUITableViewController.Back in the storyboard,select the table viewcontroller and navigateto the identity inspector.Change the custom class to“MLBLLabelViewController”.
  • 17.    17Get the Code from GitHubMake the following changes to the MLBLLabelViewController.h:Make the following changes to the MLBLLabelViewController.m:#import <UIKit/UIKit.h>#import “MLBLAppDelegate.h”#import “Label.h”@interface MLBLLabelViewController : UITableViewController// An array to house all of our fetched Label objects@property (strong, nonatomic) NSArray *labelArray;@end/* Make these changes to MLBLLabelViewController.M */@implementation MLBLLabelViewController@synthesize labelArray;- (void) viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];/* Here we call the method to load the table data */[self loadTableData];}#pragma mark - Table view data source- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{// We only need to return 1 for this table viewreturn 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{// We’ll return the count of the objects in labelArrayreturn [labelArray count];}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{static NSString *CellIdentifier = @”Cell”;UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierforIndexPath:indexPath];if (cell == nil){cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier];}
  • 18.    18Get the Code from GitHub// Configure the cell...cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;// Grab the labelLabel *label = [self.labelArray objectAtIndex:indexPath.row];// Set the text of the cell to the label namecell.textLabel.text = label.name;return cell;}#pragma mark - Private methods- (MLBLAppDelegate *)appDelegate {return (MLBLAppDelegate *)[[UIApplication sharedApplication] delegate];}// This method executes a fetch request and reloads the table view.- (void) loadTableData {NSManagedObjectContext *context = [[self appDelegate] managedObjectContext];// Construct a fetch requestNSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];NSEntityDescription *entity = [NSEntityDescription entityForName:@”Label”inManagedObjectContext:context];[fetchRequest setEntity:entity];// Add an NSSortDescriptor to sort the labels alphabeticallyNSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@”name”ascending:YES];NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];[fetchRequest setSortDescriptors:sortDescriptors];NSError *error = nil;self.labelArray = [context executeFetchRequest:fetchRequest error:&error];[self.tableView reloadData];}@endBuild and run. Based on the datawe entered in the last tutorial,you should see this:
  • 19.    19Get the Code from GitHubCreating a Navigation ControllerNow lets add to our setup: with “MLBLLabelViewController” selected in the storyboard, choose Editor> Embed In > Navigation Controller. A navigation controller is a standard UI element provided by Appleto help guide the flow of an app. It includes logic for going back to a previous view controller as well astransitions between screens. We’ve embedded “MLBLLabelViewController” as the root view controllerin our navigation controller.Drag another tableview controller onto thestoryboard. Create a new file“MLBLArtistViewController”that subclassesUITableViewController.Change the custom class of thenew table view controller to“MLBLArtistViewController”.Give it a storyboard ID of“ArtistViewController”#import <UIKit/UIKit.h>#import “MLBLAppDelegate.h”#import “Label.h”#import “Artist.h”@interface MLBLArtistViewController : UITableViewController// An array to house all of our fetched Artist objects@property (strong, nonatomic) NSArray *artistArray;//The id of the parent object@property (strong, nonatomic) NSManagedObjectID *labelID;@endMake the following changes to the MLBLArtistViewController.h:
  • 20.    20Make the following changes to the MLBLArtistViewController.m:/* Make these changes to MLBArtistViewController.m */@implementation MLBLArtistViewController@synthesize artistArray;-(void)viewWillAppear:(BOOL)animated {[super viewWillAppear:animated];[self loadTableData];}#pragma mark - Table view data source- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{// We only need to return 1 for this table viewreturn 1;}- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{// We’ll return the count of the objects in artistArrayreturn [artistArray count];}- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{static NSString *CellIdentifier = @”Cell”;UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifierforIndexPath:indexPath];if (cell == nil){cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefaultreuseIdentifier:CellIdentifier];}// Configure the cell...cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;// Grab the artistArtist *artist = [self.artistArray objectAtIndex:indexPath.row];cell.textLabel.text = artist.name;return cell;}#pragma mark - Private methods- (MLBLAppDelegate *)appDelegate {return (MLBLAppDelegate *)[[UIApplication sharedApplication] delegate];}- (void) loadTableData {NSManagedObjectContext *context = [[self appDelegate] managedObjectContext];// Construct a fetch request
  • 21.    21NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];NSEntityDescription *entity = [NSEntityDescription entityForName:@”Artist”inManagedObjectContext:context];[fetchRequest setEntity:entity];NSPredicate *predicate = [NSPredicate predicateWithFormat:@”label == %@”, [contextobjectWithID:self.labelID]];[fetchRequest setPredicate:predicate];// Add an NSSortDescriptor to sort the labels alphabeticallyNSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@”name”ascending:YES];NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];[fetchRequest setSortDescriptors:sortDescriptors];NSError *error = nil;self.artistArray = [context executeFetchRequest:fetchRequest error:&error];[self.tableView reloadData];}@endAdd #import MLBLArtistViewController.h to the MLBLLabelViewController.m file. In the - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath method, makethe following changes:- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{MLBLArtistViewController *artistViewController = [self.storyboardinstantiateViewControllerWithIdentifier:@”ArtistViewController”];// Grab the labelLabel *label = [self.labelArray objectAtIndex:indexPath.row];artistViewController.labelID = [label objectID];[self.navigationController pushViewController:artistViewController animated:YES];}Build and run, and you should be able to view the artists that are associated with a label.Next, do the same thing with albums. Create a file called “MLBLAlbumViewController” that subclassesUITableViewController, and repeat the steps for “MLBLArtistViewController”.Get the Code from GitHubGet the Code from GitHub
  • 22.    22Hold the option key and click on MLBLLabelEntryViewController.h.This will open the file side by side with the storyboard.Creating an Input ViewNow we’ll make input screens to insert data into our database.Add these two lines of code to the -(void)viewDidLoad method inMLBLLabelViewController.m:UIBarButtonItem *item = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:selfaction:@selector(addItem)];self.navigationItem.rightBarButtonItem = item;Create a file called “MLBLLabelEntryViewController”, whichsubclasses a UIViewController. Drag a view controller from theobject library onto the storyboard. Change the custom class to“MLBLLabelEntryViewController”. Drag a text field onto the viewcontroller as well. In the attributes inspector you can customize thetext field; set the placeholder text to “Enter the Label Name”.Hold the option key and click on MLBLLabelEntryViewController.h. This will open the file side by sidewith the storyboard.This establishes an outlet connection between the storyboard nib file and the view controller class.Name the outlet “labelField” and click connect.Add the following code to MLBLLabelEntryViewController.m:
  • 23.    23 Get the Code from GitHub/* Make these changes to MLBLLabelEntryViewController.m */#import “MLBLLabelEntryViewController.h”#import “MLBLAppDelegate.h”#import “Label.h”@implementation MLBLLabelEntryViewController- (void)viewDidLoad{[super viewDidLoad];// Do any additional setup after loading the view.// This will call ourUIBarButtonItem *item = [[UIBarButtonItem alloc] initWithTitle:@”Add”style:UIBarButtonItemStyleBordered target:self action:@selector(addLabel)];self.navigationItem.rightBarButtonItem = item;UIBarButtonItem *item2 = [[UIBarButtonItem alloc] initWithTitle:@”Cancel”style:UIBarButtonItemStyleBordered target:self action:@selector(dismiss)];self.navigationItem.leftBarButtonItem = item2;}#pragma mark - private methods- (MLBLAppDelegate *)appDelegate {return (MLBLAppDelegate *)[[UIApplication sharedApplication] delegate];}- (void) addLabel {// Grab the contextNSManagedObjectContext *context = [[self appDelegate] managedObjectContext];// Grab the Label entityLabel *label = [NSEntityDescription insertNewObjectForEntityForName:@”Label”inManagedObjectContext:context];// Set label namelabel.name = self.labelField.text;// Save everythingNSError *error = nil;if ([context save:&error]) {NSLog(@”The save was successful!”);} else {NSLog(@”The save wasn’t successful: %@”, [error userInfo]);}[self dismiss];}- (void) dismiss {[self dismissViewControllerAnimated:YES completion:nil];}@end
  • 24.    24 Get the Code from GitHubIn the MLBLLabelViewController.m file add #import “MLBLLabelEntryViewController.h”, add thefollowing code:// Add this method for slide to delete-(UITableViewCellEditingStyle)tableView:(UITableView *)tableVieweditingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {return UITableViewCellEditingStyleDelete;}// Override to support editing the table view.- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{if (editingStyle == UITableViewCellEditingStyleDelete) {// Delete the row from the data sourceNSManagedObjectContext *context = [[self appDelegate] managedObjectContext];// Grab the labelLabel *label = [self.labelArray objectAtIndex:indexPath.row];[context deleteObject:[context objectWithID:[label objectID]]];// Save everythingNSError *error = nil;if ([context save:&error]) {NSLog(@”The save was successful!”);} else {NSLog(@”The save wasn’t successful: %@”, [error userInfo]);}NSMutableArray *array = [self.labelArray mutableCopy];[array removeObjectAtIndex:indexPath.row];self.labelArray = array;[tableView deleteRowsAtIndexPaths:@[indexPath]withRowAnimation:UITableViewRowAnimationFade];}}// Add this method under our private methods pragma mark- (void) addItem {MLBLLabelEntryViewController *labelEntryViewController = [self.storyboardinstantiateViewControllerWithIdentifier:@”LabelEntryViewController”];UINavigationController *navigationController = [[UINavigationController alloc]initWithRootViewController:labelEntryViewController];[self presentViewController:navigationController animated:YES completion:nil];}
  • 25.    25Build it and run, and you can now add Labels to the database. You’re also able to slide to delete Labelsfrom the table, and remove them from the database. You can easily expand on this by adding input viewsfor Artists and Albums as well.What’s Next?In this tutorial, we constructed a simple UI to access and display our data. In the nextinstallment of our series, we’ll utilize the StackMob SDK to enhance our app.Download the source code for this tutorial.
  • 26.    26Part 4:Connecting to StackMobAs we noted earlier, a requirement for anything beyond thesimplest app is the ability to persist data. Another trend we’rewitnessing is the proliferation of internet enabled apps thathave some sort of backend server logic.The case for a backendIt’s very rare to find an app that doesn’t rely in some sort of fashion on a backend. Users come with theexpectation of sharing and interacting with their friends and having information delivered to them in amanner tailored to their specific interests and/or location.Some examples of these features include user creation and management, data indexing, pushnotifications and geo location coordinates. Developers deliver these features by utilizing 3rd party API’s,and ultimately, building a custom backend. Unfortunately, engineering a backend has a much steeperlearning curve than learning Core Data. You also have to manage and account for a whole host of otherpotential problems: data security, scalability, etc.Backend difficulties – and a solutionThe configuration andmanagement of a backendserver is its own ordeal, entirelyseparate from the app creationprocess. Depending on the sizeof your operation, it can range anywhere from a major nuisance to a project non-starter. Regardlessof size, the issue is relevant and real. Whether it’s an indie app maker, a startup developer or a largeenterprise organization, the prospect of building a backend is expensive in both time and resources.This is where StackMob provides value. StackMob offers a robust end to end platform for everythingrelated to your app. Through StackMob you can house your data reliably and securely, and scale tomillions of users with minimal effort. 3rd party services, API versioning, custom server code and othergreat features are available as modules in the StackMob Marketplace.
  • 27.    27Working with the StackMob SDKUsing the StackMob iOS SDK is simple and straightforward. Lets get started by incorporating it intoour MusicLabel project. If you haven’t done so already, head over to our dev center and signup for aStackMob account. The getting started page will take you through the process of signing up, creatingan app and downloading and importing the iOS SDK. Name your app “musiclabel” and select iOS as aplatform. Clicking “Step 2” will create your app.When you are finished importingthe SDK, navigate back toyour dashboard. You will seeinformation about your newlycreated app, including publicand private keys for both yourdevelopment and productionenvironments.
  • 28.    28StackMob and Core DataThe StackMob iOS SDK is tightly integrated with Core Data. The Core Data Coding Practices outlinewhat to keep in mind when using the SDK.In your Xcode project, navigate to your data model in the “MusicLabel.xcdatamodeld” file. In the Labelentity, add a string attribute titled “labelId”. Add “artistId” and “albumId” string attributes to the Artistand Album entities, respectively.Recreate your NSManagedObject subclass files. Click “Replace” when prompted.
  • 29.    29In “MLBLAppDelegate.m” make the following changes. Make sure to add your public key when initializingthe SMClient.Get the Code from GitHub#import <UIKit/UIKit.h>#import “StackMob.h”@class SMClient;@class SMCoreDataStore;@interface MLBLAppDelegate : UIResponder <UIApplicationDelegate>@property (strong, nonatomic) UIWindow *window;@property (strong, nonatomic) NSManagedObjectModel *managedObjectModel;// CODE UPDATE: Declare SMCoreDataStore instance@property (strong, nonatomic) SMCoreDataStore *coreDataStore;// CODE UPDATE: Declare SMClient instance@property (strong, nonatomic) SMClient *client;@endIn “MLBLAppDelegate.m”, we are going to initialize an SMClient instance as well as our declaredSMCoreDataStore instance. SMClient is the fundamental class for interacting with StackMob. Make sureto add your public key when initializing the SMClient.#import “MLBLAppDelegate.h”#import “Label.h”#import “Artist.h”#import “Album.h”@implementation MLBLAppDelegate// Synthesize SMCoreDataStore@synthesize coreDataStore _coreDataStore;@synthesize managedObjectModel = _managedObjectModel;// Synthesize SMClientChanges to your codeThe StackMob iOS SDK manages most of the Core Data stack, including initializing managed objectcontexts and a persistent store coordinator. Let’s edit our codebase accordingly.In the MLBLAppDelegate.h file, remove the managedObjectContext property. Remove the followingmethods in MLBLAppDelegate.m as well:• - (void)saveContext;• - (NSURL *)applicationDocumentsDirectory;• - (NSManagedObjectContext *)managedObjectContext;• - (NSPersistentStoreCoordinator *)persistentStoreCoordinator;To obtain an initialized, ready to go managed object context, SMCoreDataStore provides thecontextForCurrentThread method.Since we need to reference a local SMCoreDataStore instance to obtainmanaged object contexts, declare one in your “MLBLAppDelegate.h” file like so:
  • 30.    30Get the Code from GitHubThe SDK provides helper methods for the traditional save: and executeFetchRequest:error: Core Datacalls. They are all designed for optimal performance by adhering to common Core Data patterns andinclude asynchronous callback-based methods which are performed in the background.Edit your create method from the previous tutorials to utilize the synchronous saveAndWait: call as well asthe asynchronous saveOnSuccess:onFailure: call. Your updated code should look like this:@synthesize client = _client;- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{// Override point for customization after application launch.self.client = [[SMClient alloc] initWithAPIVersion:@”0” publicKey:@”YOUR_PUBLIC_KEY”];self.coreDataStore = [self.client coreDataStoreWithManagedObjectModel:self.managedObjectModel];/* The methods we use in the tutorial. */[self create];return YES;}// Application delegate methods remain the same. Delete the Core Data methods forNSPersistantStoreCoordinator and NSManagedObjectContext....// 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:@“MusicLabel” withExtension:@“momd”];_managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];return _managedObjectModel;}@end- (void) create {// Grab the contextNSManagedObjectContext *context = [self.coreDataStore contextForCurrentThread];// Grab the Label entityLabel *label = [NSEntityDescription insertNewObjectForEntityForName:@“Label”inManagedObjectContext:context];label.labelId = [label assignObjectId];// Set label namelabel.name = @“Diplomat Records”;
  • 31.    31Get the Code from GitHub// Create a DateNSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];[dateFormatter setDateFormat:@“YYYY”];NSDate *dateFounded = [dateFormatter dateFromString:@“2003”];// Set the year founded for the labellabel.founded = dateFounded;// Set the label genrelabel.genre = @“Rap/Hip-hop”;// Insert the Artist entityArtist *artist = [NSEntityDescription insertNewObjectForEntityForName:@“Artist”inManagedObjectContext:context];artist.artistId = [artist assignObjectId];// Set the artist attributesartist.name = @“Cam’Ron”;artist.hometown = @“Harlem, NY”;// Insert Album entityAlbum *album = [NSEntityDescription insertNewObjectForEntityForName:@“Album”inManagedObjectContext:context];album.albumId = [album assignObjectId];// Set album attributesalbum.title = @“Come Home With Me”;NSDate *releaseDate = [dateFormatter dateFromString:@“2002”];album.released = releaseDate;// CODE UPDATE: Use the synchronous save method saveAndWait:NSError *error = nil;if (![context saveAndWait:&error]) {NSLog(@“The save wasn’t successful: %@”, [error userInfo]);} else {NSLog(@“Save successful”);}// Set relationships[label addArtistsObject:artist];[artist setLabel:label];[artist addAlbumsObject:album];[album setArtist:artist];// CODE UPDATE: Use the asynchronous save method saveOnSuccess:onFailure:[context saveOnSuccess:^{NSLog(@“Successful relations update”);} onFailure:^(NSError *error) {NSLog(@“Unsuccessful relations update with error %@”, error);}];}
  • 32.    32Get the Code from GitHubThe key thing to remember is that any NSManagedObject must have an id assigned to it before it issaved to StackMob. In “MLBLLabelEntryViewController.m” add the following line to the -(void) addLabelmethod:label.labelId = [label assignObjectId];Go ahead and edit all the save:error and executeFetchRequest:error: calls throughout your codebase toutilize the StackMob methods. In all your .m files you will want to assign your managedObjectContextvariables to [[[self appDelegate] coreDataStore] contextForCurrentThread];, which may require you toadd #import “StackMob.h” as well. More information on all the available methods to interact with CoreData can be found in the NSManagedObjectContext+Concurrency reference.Build and run, and check your dashboard. Under “Schema Configuration”, you should see the entities youcreated, alongside the “user” schema.- (void) delete {// Grab the contextNSManagedObjectContext *context = [self.coreDataStore contextForCurrentThread];// We’re looking to grab an artistNSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];NSEntityDescription *entity = [NSEntityDescription entityForName:@”Artist”inManagedObjectContext:context];[fetchRequest setEntity:entity];// We specify that we only want Freekey ZekeyNSPredicate *predicate = [NSPredicate predicateWithFormat:@“name == %@”, @“Freekey Zekey”];[fetchRequest setPredicate:predicate];// CODE UPDATE: Nest the asynchronous save call in the asynchronous fetch call.[context executeFetchRequest:fetchRequest onSuccess:^(NSArray *results) {// Grab the artist and deleteArtist *freekey = [results objectAtIndex:0];[freekey.label removeArtistsObject:freekey];// Save everything[context saveOnSuccess:^{NSLog(@“The save was successful!”);} onFailure:^(NSError *error) {NSLog(@“The save wasn’t successful: %@”, [error localizedDescription]);}];} onFailure:^(NSError *error) {NSLog(@“Error fetching: %@”, error);}];}Let’s take a look at another updated CRUD method we’ve created, the delete method. Here, we see thesaveOnSuccess:onFailure: call wrapped in the callback of the executeFetchRequest:onSuccess:onFailure:call. Edit your code to look like the following:
  • 33.    33There you have it! With a few steps and very little additional code, we’ve seamlessly integratedStackMob into our Core Data stack.What’s Next?Be sure to check out the StackMob iOS SDK Reference for more information on using theStackMob iOS SDK. Also, take a look at our iOS tutorials for helpful examples.Download the source code for this tutorial. For more information, visit out blog.Click on “Data Management” and you’ll be able to query the objects you’ve saved.