Beginning iOS Development: Data Persistence

Beginning iOS Development: Data Persistence

Tutorial Details
  • Completion Time: 45 - 60 Minutes
  • Difficulty: Beginner
  • Technology: iOS SDK
This entry is part 7 of 7 in the series Beginning iOS Development

In the seventh installment of the Beginning iOS Development screencast series, we are looking at Data Persistence in iOS Applications. The screencast includes a short keynote overview of the different storage methods that you can use in an iOS application as well as the pros and cons of each method. After the keynote, the four implemented data storage methods are explained in detail.

As mentioned in the screencast, this demo application implements all four data storage methods. If you wish to implement one of them into your own application use the demo application given as a guide only.

Trouble watching the video above? Download the full quality version in MOV format here.

Further Information

Property Lists

Property List documents are an archived tree of objects. The Property List contains a root element which is either an NSDictionary or an NSArray. Inside the root element is the archived data. The classes that can be archived into a Property List are: NSString, NSNumber, NSData, NSDate, NSArray and NSDictionary. Providing any other objects to be archived as a property list will not write the file. A common mistake is to give a Boolean or Integer object to one of the items in the NSArray or NSDictionary. To store a Boolean or Integer use the NSNumber class.

SQLite

As mentioned, using the SQLite C library can be tricky the first time around as it is very particular about the argument types given to functions. It’s important to remember the differences when passing in strings and the arguments required for these functions.

If you want to bypass the C library there are a few Objective-C wrappers written for using SQLite on the iOS. FMDB is one particular wrapper that you can include into your Xcode project to avoid using the C library.

Seeding

SQLite operates from a single file. When the application is launched for the first time you will have to run a file creation process to make the SQLite file available. In the screencast implementation a new blank SQLite database is created and SQL executed to setup the first table. However, you may want to have a database that has data already seeded into it. To do this you create a SQLite file with the table schema and required data inserted and then include the file into your Xcode project. In the database initialization process you can then copy the seed SQLite file from your Resources bundle to your application’s Documents directory.

SQLite command reference

For more information on the functions available in the SQLite library go to the SQLite C Interface Functions List.

Core Data

When implementing Core Data it is important to remember to create your Xcode project with the “Use Core Data for storage” option checked. That option will create some required properties and methods in your Application Delegate as well as include the Core Data framework into your project.

Core Data uses SQLite by default as the main database in your application. The Core Data framework in the iOS allows for 2 different database storage types and by default it is SQLite.

Getting started tutorials for Core Data

If you want a deeper guide on using Core Data for the first time then check out the First steps with Core Data article.

User Defaults (NSUserDefaults)

This method is different from the other 3 in the screencast. It is not used for storing collections of data as demonstrated in the other 3 implementations. Information stored in this method should be limited to user changeable settings and options.

Storing user authentication information

When storing usernames and passwords it is better to use the Keychain service available in the iOS. The Keychain is a secure storage medium to keep user authentication information on the device in a secure and encrypted manner. For more information on the Keychain go to the Keychain Services Programming Guide in the Apple Documentation.

Thanks for watching this screencast. If you have any further questions please drop a comment in below.

Series Navigation«Beginning iOS Development: Debugging Fundamentals

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://twitter.com/patelaxit Axit Patel

    I must this is one of the best tutorials on Mobiletuts+! Keep up the good work :)

  • http://twitter.com/patelaxit Axit Patel

    I must say that this is one of the best tutorials on Mobiletuts+! Keep up the good work :)

    • http://alexeckermann.com/ Alex Eckermann
      Author

      Cheers thanks Axit! I was hoping people didn’t get lost half way through there :P

  • begs

    Oh yes, again this is one great tut. It’s very easy to follow your words and thoughts.
    Keep up the good work and:

    A BIG Thank you!

  • http://www.lamiscela.net Junio Vitorino

    Hi Alex, this series is great, i’ve just one ask. Do you also can release the video file in high definition to download? Thus, we also can watch on tv room eating a delicious popcorn.

    Thanks and congratulations.

  • http://www.lamiscela.net Junio Vitorino

    Oooh! Alex sorry, you already releases the file to download, i not saw. =(

  • Matt Price

    Hi Alex,

    I’ve not watched this yet, but have watched every other video in the series so far and love what yourself and mark have done.

    Does MobileTuts upload videos to iTunes so you can subscribe to them? I know NetTuts used to do this!

    Keep up the great work, Many Thanks

    Matt

    • http://alexeckermann.com/ Alex Eckermann
      Author

      Hi Matt.

      Ill pass the suggestion onto Mark and see if its possible.

      Cheers.

  • Quoc Khanh

    Hi, Thank you for your tutorial, but I can’t download this video. Can you re-upload it?

    • http://alexeckermann.com/ Alex Eckermann
      Author

      Hi.

      I just checked out the MOV download and it looks like its working fine. It does take a while to get enough buffered up to play, it is full 720p.

      Let us know if you are still having issues.

      Cheers.

  • http://bohtech.com David DelMonte

    Great Video and tutorial Alex, thanks a ton..

    One question – your methods work (in each example) because you are have two data elements (name and price).

    So can use this create method in CoreData for example:

    createNewRecordWithName:(NSString *)arg_name andPrice:(NSNumber *)arg_price

    What do you suggest when you have more that two elements? How would you invoke the create or update methods?

    I’m asking as the following invocation will not work with more than two parameters:

    performSelector:@selector(createNewRecordWithName:andPrice:) withObject:[nameField text] withObject:priceNumber];

    Thank you again for your hard work.

    David

    • http://alexeckermann.com/ Alex Eckermann
      Author

      Hi David.

      I have encountered what you have described. I overcame it by just calling the method outright without the performSelector:withObject: method. After the sanity check on the class is done, to make sure the selector exists/responds, I just assume its all ok to use normally.

      That should fix your problem :)

      Thanks for watching.

  • Sasquatch Software

    All throughout this code there are memory leaks.

    Example 1: AppUserSettingsModalController.h/m

    in header file:
    <pre name="code"
    @property (nonatomic, retain) UINavigationBar *navBar;

    in initwithnibname:
    <pre name="code"
    self.navBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0,0,320,44)];

    in dealloc:
    <pre name="code"
    [navBar release]

    this will end with +1 count

    see http://stackoverflow.com/questions/156243/object-allocate-and-init-in-objective-c

  • Jesse

    Hey great tutorials they have been really helpful in my quest to create an iPhone application. Is it possible to pull information from a database on a server and display it in the iPhone app ?

    • http://www.google.com/ Charl

      Grade A stuff. I\’m unuqesitoanbly in your debt.

  • Rehan Lakhani

    Is there any possible way you could post the structure of the plist that is created, because I have written exactly what you have here and it still does not write to the plist

  • http://twitter.com/jakerocheleau Jake Rocheleau

    Still getting a bit used to all of this… but yeah really fantastic stuff guys. I’m looking forward to practicing on my first iOS app launch!

  • Mark

    Hey Im trying to extend the FortuneCrunch App by using a plist to randomly display the “fortune” on the cookie but I am having trouble with it. I have a plist with an array and a few items.

    -(void)viewDidLoad {
    [super viewDidLoad];

    NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
    NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"fortuneList.plist"];

    if ([[NSFileManager defaultManager] fileExistsAtPath:plistPath]) {
    self.genFortune = [NSArray arrayWithContentsOfFile:plistPath];
    }
    else {
    self.genFortune = [[NSArray alloc] init];
    }

    }

    -(IBAction)crunchCookie:(id)sender {
    NSLog(@”[self.generateFortune]“);
    [fortuneCookieButton setImage:[UIImage imageNamed:@"cookie-crunched.png"] forState:UIControlStateNormal];
    fortuneLabel.text = [self generateFortune];
    fortuneLabel.hidden = NO;
    newFortuneCookieButton.hidden = NO;
    }

    -(IBAction)unCrunchCookie:(id)sender {
    [fortuneCookieButton setImage:[UIImage imageNamed:@"cookie-closed.png"] forState:UIControlStateNormal];
    fortuneLabel.hidden = YES;
    newFortuneCookieButton.hidden = YES;
    }

    -(NSString *)generateFortune {
    int chosen_index = arc4random() % 3;
    return [genFortune objectAtIndex:chosen_index];

    }

    as you probably noticed, I am a total noob at this. The error that I get is “-[NSArray objectAtIndex:]: index 1 beyond bounds for empty array”

    I asume this would be if I was missing an array but I have one. I get no errors or warnings when I build and debug. This happens when I press on the “cookie”. Thanks for the tuts!!

    • http://www.creativethemez.com Mark

      OK so I figured it out..

      NSString *dataPath = [[NSBundle mainBundle] pathForResource:@”fortuneList” ofType:@”plist”];
      NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:dataPath];
      genFortune = [plistDict objectForKey:@"genFortune"];

      instead of

      NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
      NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"fortuneList.plist"];
      if ([[NSFileManager defaultManager] fileExistsAtPath:plistPath]) {
      self.genFortune = [NSArray arrayWithContentsOfFile:plistPath];
      }
      else {
      self.genFortune = [[NSArray alloc] init];
      }

      • http://www.creativethemez.com Mark

        OK so I figured it out:

        Instead of:
        NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"fortuneList.plist"];
        if ([[NSFileManager defaultManager] fileExistsAtPath:plistPath]) {
        self.genFortune = [NSArray arrayWithContentsOfFile:plistPath];
        }
        else {
        self.genFortune = [[NSArray alloc] init];
        }

        I used:
        NSString *dataPath = [[NSBundle mainBundle] pathForResource:@”fortuneList” ofType:@”plist”];
        NSMutableDictionary *plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:dataPath];
        genFortune = [plistDict objectForKey:@"genFortune"];

        —I do have another question, When the user preses on the button the label refreshes with new “fortunes” if it is already open. . I have a seperate button that puts the “cookie” back together so I want the label to only display an item once and not x amount of times the user presses on the cookie. basically the user presses on the cookie, the fortune displays and thats it until the user presses a different button that “resets” the cookie. This is the code for the two buttons when pressed

        //generates fortune
        -(IBAction)crunchCookie:(id)sender {
        [fortuneCookieButton setImage:[UIImage imageNamed:@"cookie-crunched.png"] forState:UIControlStateNormal];
        fortuneLabel.text = [self generateFortune];
        fortuneLabel.hidden = NO;
        newFortuneCookieButton.hidden = NO;
        }

        //resets the cookie button
        -(IBAction)unCrunchCookie:(id)sender {
        [fortuneCookieButton setImage:[UIImage imageNamed:@"cookie-closed.png"] forState:UIControlStateNormal];
        fortuneLabel.hidden = YES;
        newFortuneCookieButton.hidden = YES;
        }

        by do i need to “close/kill” the DB after its finished with its function?

  • http://www.creativethemez.com Mark

    I figured it out.. I need to use my web dev background more to figure these things out..lol

    -(IBAction)crunchCookie:(id)sender {
    [fortuneCookieButton setImage:[UIImage imageNamed:@"cookie-crunched.png"] forState:UIControlStateDisabled];
    fortuneLabel.text = [self generateFortune];
    fortuneLabel.hidden = NO;
    newFortuneCookieButton.hidden = NO;
    fortuneCookieButton.enabled=NO;
    }

    -(IBAction)unCrunchCookie:(id)sender {
    [fortuneCookieButton setImage:[UIImage imageNamed:@"cookie-closed.png"] forState:UIControlStateNormal];
    fortuneLabel.hidden = YES;
    newFortuneCookieButton.hidden = YES;
    fortuneCookieButton.enabled = YES;
    }

    If there is a better/shorter way of doing all this above, please post. Thanks

  • caxarock

    are we going to get new tutorials ? :) I’ve worked out all provided :(

  • BiGGA

    Great tutorial. To the point. Precise and the timing is just about right.

  • Sahnil

    As per above common mistake in plist aka property list is “A common mistake is to give a Boolean or Integer object to one of the items in the NSArray or NSDictionary” but essentially this isn’t possible since we can not add a Int or bolean to dictionary nor an array.