Tutorial on How-To Add Core Data to a New or Existing iOS App | iPhone | iPad

Most of Core Data examples online or in textbooks are mostly all built using a navigation view controller (UINavigationController). They also feature a UITable and or a UITableView as part of their design. But what if you wanted to create an iPhone or iPad app which doesn’t use these elements? Or what if you needed to create a Core Data app from scratch? Or you wanted to add Core Data to an existing app? All valid questions.

They are all answered with this tutorial. In fact this tutorial shows how to build a Core Data app from scratch using a Single View Controller. It takes you through all the easy steps to setup Core Data in a new or existing app that doesn’t use a navigation controller or a table view or table view controller.

This tutorial will demonstrate how to setup Core Data from scratch and store audio files in a Core Data storage facility. In the next tutorial I will fetch and playback the audio files.

Setup the Project


To begin create a Single View Controller application. Make sure to enable ARC in the options, see figure 1. Once the project is saved to disk and loaded we will setup the necessary code to add Core Data to the project

Figure 1 : Create a Single View Controller
Figure 1 : Create a Single View Controller

Setup Core Data - Add the framework


The first step towards adding Core Data to a project is adding the Core Data framework. You can accomplish this selecting the project root in the navigator, then select the application target and scroll down on the Summary page to the Linked Frameworks and Libraries section and click on the + button. In the popup, type in the Core Data in the search field and click the “Add” button to add the framework to the project. The library will be added to the Resource folder, so select it and drag it to the Frameworks group in the Navigator. See the adjacent screenshot below.

Figure 2: Add Core Data Framework
Figure 2: Add Core Data Framework

Setup Core Data - Add Data Model


Building a Core Data application requires a Data Model file which will allow you to define the Entities, Attributes, Relationships and Predicates. The template is located in the New File popover under Core Data in the iOS group.

The name of the Data Model file is important since you must use it explicitly later on in the Application Delegate when loading the Managed Model into memory when the application is launched.

Once the file is created, you will see it in the project navigator. It has a “xcdatamodeld” file extension. Open it and add an Entity, which will be represented in the SQLite database as the table. To create an Entity, click on the “Add Entity” button at the bottom of the page. The Entity name must start with a Capital letter. For this tutorial, I will create an Entity called “Audios” so that I may store audio files in my Core Data storage facility.

The second part of data model for this tutorial is to add Attributes to the Entity. You can view Attributes as being the columns in the table(s) in the SQLite storage facility. By contrast Attribute names must start with lowercase letter. Attributes can be added by clicking on the “Add Attribute” button at the bottom of the page or by clicking on the “+” sign in the Attribute section.

For this tutorial I will add two Attributes, one called “name” and will have a string data type and the other will be called “audioFile” and will have a Binary Data data type to hold the actual binary representation of the audio file.

Take a look at the screenshot below to see how the data model should be laid out in the Core Data Editor. For this tutorial we don’t need any relationships or predicates. The next part will setup the Core Data objects in the Application Delegate.

Figure 3: Core Data Model Template
Figure 3: Core Data Model Template
Figure 4: Core Data Editor
Figure 4: Core Data Editor

CoreDataAudioIPHone-Prefix.pch Setup


It is also crucial to add the CoreData framework to the CoreDataAudioIPHone-Prefix.pch file. This file is used by iOS applications to precompile the app during the compilation. Precompilation is a technique to accelerate the compilation process.

Prefix.pch Code

#import <Availability.h>

#ifndef __IPHONE_5_0
#warning "This project uses features only available in iOS SDK 5.0 and later."
#endif

#ifdef __OBJC__
    #import <UIKit/UIKit.h>
    #import <Foundation/Foundation.h>
    #import <CoreData/CoreData.h>
#endif

Application Delegate-Header


The main Core Data configuration happens in the AppDelegate header and implementation files. You will need to create the NSManagedObjectContext, NSManagedObjectModel and NSPersistentStoreCoordinator objects to be globally accessible to the different view controllers in a given application like your own. Here are the steps to setup the AppDelegate header file:

1-Import the CoreData header file to gain access to the its API
2-Add the @class directive to the view controller that will be used for the root controller
3-Add a NSManagedObjectContext instance variable as nonatomic, retain and readonly.
4-Add a NSManagedObjectModel instance variable as nonatomic, retain and readonly.
5-Add a NSPersistentStoreCoordinator instance variable as nonatomic, retain and readonly.
6-Next add a method, applicationDocumentsDirectory, that will return the path as a NSURL of the SQLite database that will be used by Core Data.
7-Lastly, create another method, saveContext, to capture the current configuration of the current context to save as the application gets unloaded.
The code listing below is sample header AppDelegate file from the tutorial but it is the minimum code requirement to setup Core Data with no Navigation Controller or Tabbed Navigation Controller

AppDelegate - Header Code

#import <UIKit/UIKit.h>
#import <CoreData/CoreData.h>

@class ViewController;
@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator;

- (NSURL *)applicationDocumentsDirectory;
- (void)saveContext;

@end

Application Delegate-didFinishLaunchingWithOptions



The next major step involves implementing the Core Data code in the AppDelegate implementation file. This file includes many crucial pieces of code and many required methods to make your Core Data application work properly.

Start by opening the AppDelegate file and synthesizing the variables as the following shows:

AppDelegate - Implementation Code

#import "AppDelegate.h"
#import "ViewController.h"

@implementation AppDelegate

@synthesize window = _window;
@synthesize managedObjectContext=__managedObjectContext;
@synthesize managedObjectModel=__managedObjectModel;
@synthesize persistentStoreCoordinator=__persistentStoreCoordinator;

Notice how the ViewController header is imported. This is important as we will need to define which view controller (or navigation view controller) will be the root view controller. The next lines of code sets up the instance variables that will be used by Core Data.

The didFinishLaunchingWithOptions method is very important as it creates the context, model and SQLite database by the NSManagedContext which in turn will create and initialize the other objects

Since this example is using only using a view controller, we will start creating a new ViewController object and defining it as the root view controller for the application. Then we will set the managedObjectContext of the root controller to the managedObjectContext variable. This line of code will trigger the app to call the other required methods, that we will look next, to setup the Core Data objects.

didFinishLaunchingWithOptions Code

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
   

    ViewController *controller = (ViewController *)self.window.rootViewController;
    controller.managedObjectContext = self.managedObjectContext;

    [self.window makeKeyAndVisible];
    return YES;
}

Application Delegate-managedObjectContext


The managedObjectContext method and its associated code is provided as is. Meaning all you need to do is copy and paste into the AppDelegate implementation file. The code will setup and return the context and create the related NSPersistentStoreCoordinator.

managedObjectContext Code

- (NSManagedObjectContext *)managedObjectContext
{
    if (__managedObjectContext != nil)
    {
        return __managedObjectContext;
    }
    
    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil)
    {
        __managedObjectContext = [[NSManagedObjectContext alloc] init];
        [__managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return __managedObjectContext;
}

Application Delegate-managedObjectModel


The managedObjectModel method returns the object model or creates it if doesn’t exist. Here you need to add the name of your object model. In this tutorial it is “CoreDataAudioIPHoneDM” which is the name of the Core Data model filename without the extension. It is important to specify the exact same name as the object model filename or your application will crash.

managedObjectModel Code

- (NSManagedObjectModel *)managedObjectModel
{
    if (__managedObjectModel != nil)
    {
        return __managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"CoreDataAudioIPHoneDM" withExtension:@"momd"];
    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];    
    return __managedObjectModel;
}

Application Delegate-persistentStoreCoordinator



The persistentStoreCoordinator method creates or returns the persistentStoreCoordinator object which is the Sqlite database. The name of the SQLite database is usually the name of the application, so we will continue to this practice and change the name of the database to our application name.

You don’t need to change anything else in the code except that in a production app you would need to replace the abort() method by a popover or a UIAlertView information the user that the application has crashed and they need to click on the “Home” to reset the application.

persistentStoreCoordinator Code

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil)
    {
        return __persistentStoreCoordinator;
    }
    
    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"CoreDataAudioIPHone.sqlite"];
    
    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        //Don't use abort() in a production environment. It is better to use an UIAlertView
        //and ask users to quick app using the home button.
        abort();
    }    
    
    return __persistentStoreCoordinator;
}

Application Delegate-applicationDocumentsDirectory


This method isn’t strictly required. It is considered a helper method as is returns the path of the Documents directory that is used in the persistentStoreCoordinator method to setup and initialize the SQLite database.


applicationDocumentsDirectory Code

- (NSURL *)applicationDocumentsDirectory
{
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
}

Application Delegate-saveContext


The saveContext is not a required method but is can be used when the application is closing down to save state and content changes.

saveContext Code

- (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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
             */
            NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
            abort();
        } 
    }

}

The above methods and variables are the necessary components to successfully setup and use Core Data in an application. The remaining of the tutorial demonstrate how to implement the Core Data configuration. The application, which by the way is not recommended for a production grade app, will allow a user to select an audio filename using an UIPickerView control and saves the binary representation of the audio file in a Core Data storage facility. This is only for demonstration purposes because in a real app this technique would eat up the system resource in an alarming rate, but you can use the same technique with other types of file or data.

ViewController - Header file


To successful implement Core Data in an application you will first need to create assign the NSFetchedResultsControllerDelegate to be able to respond to the events and gain access to the delegate method: - (NSFetchedResultsController *)fetchedResultsController. Also to use the UIPickerView, we will need to implement the UIPickerViewDelegate protocol which will respond to certain events that we will look later. The UIPickerViewDataSource protocol allows us to assign a data source to the UIPickerView

Next we will define four instance variables. One for the NSFetchedResultsController and another one for the NSManagedObjectContext which are the minimum implementation requirements. The app will also need an array variable to be used as a data source for the UIPickerView and finally we will create an IBOutlet for the UIPickerView which is the last instance variable.

To handle the Core Data operations for storing data, we will create two methods: getAudioBinary which will return the binary representation of the audio file and will be used in the insertNewManagedObject method to store the data. The code for the header file is listed below.

ViewController Header Code

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController<NSFetchedResultsControllerDelegate,UIPickerViewDelegate, 
UIPickerViewDataSource> 

@property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
@property (nonatomic, strong) NSArray *onlyAudioFiles;
@property (strong, nonatomic) IBOutlet UIPickerView *audioFileList;

-(NSData *)getAudioBinary:(NSString *)fileName;
-(void)insertNewManagedObject:(NSString *)fileName;


@end

ViewController - Implementation


The final of the development of this app involves implementing the Core Data stack in the ViewController implementation file. Other than the custom instance method that we have declared in the header file, the application will use the ViewController’s viewDidLoad method to setup the UIPickerView and will also implement the UIPickerViewDelegate required method which we will look at in the following sections.

First thought we will need to synthesize our variables at the top of the implementation file right after the ViewController @implementation directive. Also we will need to import the CoreData library. See the code listing below.

ViewController Implementation Code

@implementation ViewController
@synthesize audioFileList;
@synthesize fetchedResultsController,managedObjectContext, onlyAudioFiles;

ViewController - viewDidLoad


The viewDidLoad is the workhorse for the app. The first variable, a NSString called root, gets a handle on the Resource folder where the audio files are located. The next line defines a NSFileManager variable which we will use to get the contents of the Resource directory using the contentsOfDirectoryAtPath passing in the root path. This will return all contents as an array (NSArray) but since we only want the audio files, we will use a NSPredicate to apply a filter to the dirContents NSArray, which we will assign to another NSArray, onlyAudioFiles. We will use the onlyAudioFiles as our data source for the UIPickerView.

The last line initializes the UIPickerView and since we have implemented the UIPickerViewDelegate, this will trigger the required instance methods that we will look at in the next section. The code for the viewDidLoad method is listed below.

viewDidLoad Code

- (void)viewDidLoad
{
    [super viewDidLoad];
  
    NSString *root = [[NSBundle mainBundle] bundlePath];
    NSFileManager *fileMgr = [NSFileManager defaultManager];
    NSArray *dirContents = [fileMgr contentsOfDirectoryAtPath:root error:nil];
    NSPredicate *extFilter = [NSPredicate predicateWithFormat:@"self ENDSWITH '.wav'"];
    onlyAudioFiles = [dirContents filteredArrayUsingPredicate:extFilter];
    
   [self.audioFileList selectRow:1 inComponent:0 animated:NO];
}

ViewController - pickerView Required Methods


The UIPickerViewDelegate protocol define several instance method to allow the control to respond to events. The – pickerView:titleForRow:forComponent:
is partially optional. By this I mean you can either implement this method or the – pickerView:viewForRow:forComponent:reusingView:. These methods are used to assign the content to the UIPickerView. For this example we will use the former which will assign the contents of the onlyAudioFiles NSArray. The code for the method implementation is provided below.

The other method that must be implemented in the delegate is the pickerView:didSelectRow:inComponent: which is called when a user selects an item in the UIPickerView. The method returns the name of the selected item and will pass it to the insertNewManagedObject method, see the code below.

The other protocol implemented is the UIPickerViewDataSource. This protocol implements the numberOfRowsInComponent method which is the number of columns to display in the UIPickerView. For this tutorial, we will set it to 1.

The pickerView:numberOfRowsInComponent: is a required method in the UIPickerViewDataSource protocol. This method returns number of rows the control will have to work with which is the number of items in the onlyAudioFiles NSArray. The code for all the method are provided below.

numberOfComponentsInPickerView Code

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
{
    return 1;
}

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
    [self insertNewManagedObject:[onlyAudioFiles objectAtIndex:row]];
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
{
    return [onlyAudioFiles count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component;
{
    
    return [onlyAudioFiles objectAtIndex:row];
}

ViewController - getAudioBinary


The getAudioBinary method will be used to get the binary representation of the audio files and return as a NSData object. The method uses the filename parameter to build the complete path along with the root variable which contains the path to the Resource directory.

Using the resulting filePath variable as the input parameter for the initWithContentsOfFile, the latter will return the binary representation of the file as an NSData object which will be used by the insertNewManagedObject.

getAudioBinary Code

-(NSData *)getAudioBinary:(NSString *)fileName{
    NSString *root = [[NSBundle mainBundle] bundlePath];
    NSString *filePath = [[NSString alloc] initWithString:[root stringByAppendingString:[@"/"stringByAppendingString:fileName]]];
    
    NSLog(@"%@",filePath);

    NSData *audioData = [[NSData alloc] initWithContentsOfFile:filePath];
    return audioData;

}

ViewController - insertNewManagedObject



This method handles the interaction with Core Data SQLite database by inserting new data. The context variable is assigned the context that we have initialize in the AppDelegate that is fetched by fetchedResultsController method. Once the context is assigned, we can our entity description which returns information on the entity, the same way we use the id to decribe an object. We will use this to create a new NSManagedObject using the insertNewObjectForEntityForName method that will receive the NSEntityDescription variable, entity and the its name property. The second required parameter is the active context, or session.

Once the NSManagedObject is created, it is a simple task to its attributes. The first one is name, and will contain the selected filename, and the second attribute will receive the NSData value returned by the getAudioBinary method.

The rest of the code, listed below, is provided to capture any processing errors. As previously noted, replace the abort() in a production app with a popover and return directive. The user should be notified that the operation failed, possibly providing and error message anf what further actions may be taken.

insertNewManagedObject Code

-(void)insertNewManagedObject:(NSString *)fileName{

// Create a new instance of the entity managed by the fetched results controller.

NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];


NSEntityDescription *entity = [[self.fetchedResultsController fetchRequest] entity];

NSManagedObject *newManagedObject = [NSEntityDescription insertNewObjectForEntityForName:[entity name] inManagedObjectContext:context];


// If appropriate, configure the new managed object.

// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.

[newManagedObject setValue:fileName forKey:@"name"];

[newManagedObject setValue:[self getAudioBinary:fileName] forKey:@"audioFile"];


// Save the context.

NSError *error = nil;

if (![context 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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.

*/

NSLog(@"Unresolved error %@, %@", error, [error userInfo]);

abort();

}



}

ViewController - fetchedResultsController


The fetchedResultsController is the last method that we must implement to make our Core Data implementation work. This method fetches the entity that we will use to save our data. This method handles the return messages or query results from Core Data. You can use the code as is, replacing the value for the entity that you need to use. You can also set the sort attribute.

fetchedResultsController Code

- (NSFetchedResultsController *)fetchedResultsController
{
if (fetchedResultsController != nil)
{
return fetchedResultsController;
}

/*
Set up the fetched results controller.
*/
// Create the fetch request for the entity.
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Audios" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];

// Set the batch size to a suitable number.
[fetchRequest setFetchBatchSize:20];

// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

[fetchRequest setSortDescriptors:sortDescriptors];

// Edit the section name key path and cache name if appropriate.
// nil for section name key path means "no sections".
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;



NSError *error = nil;
if (![self.fetchedResultsController performFetch:&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. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}

return fetchedResultsController;
}

Running the Application

With all the pieces in place, all that is required is to run the app. With this tutorial you have all the necessary parts to either add Core Data to an existing application or to add Core Data to a new application without using a pre existing template. Also this tutorial assumes you aren't using a Navigation Controller or a Tabbed Navigator.


Figure 5: Running App
Figure 5: Running App

More by this Author


Comments 19 comments

carl grainger 4 years ago

Thanks, the next tutorial should be interesting I was unaware iOS supported playing .wav files!


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

I am working on audio playback from stored binary files. Should be ready soon. Stay tuned :)


Georgiana 4 years ago

Hey man did you finish your tutorial?


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Hi Georgiana

Almost, I was stuck on a project that was taking too much of my time. I

should complete by next week.


pdschuller 4 years ago

Very helpful. Thanks. In your intro paragraphs you say that you will show how to add core data to an existing app. I don't see where you show that.

I have an existing app that has a tab controller in an existing storyboard. I don't see how I can instantiate those from AppDelegate.m to get the CoreData stuff into them. I'm a relative newb.

Thanks.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

Hi pdschuler,

the process outlined in the article is the same for a new or existing app. for an existing app, add an import statement to your (existing) tab controller in the appDelegate. In the didFinishWithOptions create a new instance of your tab controller and set it as the root as in the example above.


Alex 3 years ago

Hello

Very helpful tutorial, i'm trying to use the technique to record audio files ans store with core data but no success. Can you help me?Do you have an tutorial about this?

Thanks


Alex 3 years ago

Hello

Very helpful tutorial, i'm trying to use the technique to record audio files ans store with core data but no success. Can you help me?Do you have a tutorial about this?

Thanks


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

Hi Alex,

Sorry for the late reply I have been away. Take a look at this tutorial I wrote. In this tutorial I am using images but the principle is the same for audio files which can be converted to NSData (binary) for storage. I don't have a tutorial but I could adapt this one

Kevin


Alex 3 years ago

Hi

Thank you very much for your replay i really appreciate. I've seen your tutorial where you use images the problem is that your images are in Resource what i want when i record audio and press save the audio to go in a table view.

I will appreciate very much if you can adapt one of your tutorial


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

Hi Alex,

I will put together a tutorial for you.

Kevin


Alex 3 years ago

Hi Kevin,

Thanks it will be very helpful.

My regards

Alex


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

I am swamped with projects, but I have started writing the tut


Alex 3 years ago

Hi Kevin

Still didn't figure out about recording audio, please can you tell me if the song is save in document directory how to take the path and store in a tableview?

My regards

Alex


shandy 3 years ago

Hello sir,

I am a graduate student. Sir please upload the code for my task " When the user selects a date from the datepicker he has to navigate to a new viewcontroller showing the selected date " please help me for this issue. I searched a lot but i couldn't find the answer if you post this answer it will help me a lot for getting a job for me.

With Regards,

Shandy.


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

hi shandy

that is fairly easy. Use the Exit (Unwind) option in the view controller. Check out this tutorial:

http://hubpages.com/technology/iOS-6-Storyboard-Un...


Mike 3 years ago

Hi I have tried to implement this into an existing programme but get this error -[UINavigationController setManagedObjectContext:]: unrecognized selector sent to instance 0x952c900 can you help?


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

Your object is not properly set


klanguedoc profile image

klanguedoc 20 months ago from Canada Author

Amit

I didnèt write the tutorial you are referring to on youtube. Please contact the author directly. If you want to create a checkbox programmatically, you can take a look my tutorial here:

http://hubpages.com/technology/iOS-Create-Custom-B...

    Sign in or sign up and post using a HubPages Network account.

    0 of 8192 characters used
    Post Comment

    No HTML is allowed in comments, but URLs will be hyperlinked. Comments are not for promoting your articles or other sites.


    Click to Rate This Article
    working