STEMAcademiaAgriculture & FarmingHumanitiesSocial Sciences

Tutorial on Creating an iOS SQLite Database Application for iOS, iPhone, or iPad

Updated on January 31, 2017
klanguedoc profile image

Kevin is Software Developer with 20 years experience designing and building software applications including iOS and Android apps.

The essentials to master how to develop iOS apps  for iPhone and iPad using SQlite
The essentials to master how to develop iOS apps for iPhone and iPad using SQlite | Source

(c) klanguedoc, 2011

iOS and SQLite make a powerful combination for building data persistent iPad, iPhone or iPod Touch mobile applications. The iOS SDK provides native support for SQLite through the use of the C programming language. This tutorial will walk you through how to setup a SQLite database application and to read text and images from the database into a scene.

Create the database


To start with, you will need FireFox from Mozilla and the SQLite Database Manager plugin. If you don’t have them, they can be downloaded and installed from the FireFox web site. Once FireFox is installed, install the SQLite Manager from the Add-on Manager.

The SQLite Manager can be launched from the Firefox menu or Tools menu depending on the version you are using (see figure 1).

Figure 1: SQLite Manager in Firefox
Figure 1: SQLite Manager in Firefox

Click on the new Database button (figure 2) to create a new database. You can give any meaningful name you want. Note, the SQLite extension will be automatically appended. You will be prompted to save the file to the file system, (naturally). Take note where you are saving it because you are going to copy the file later into your project.

Next, click on the new table button (figure 3) to create a new table, again I will leave it up to you to name it something useful. For this tutorial, my named the table wineTbl and I have created four columns: id [primary, autoinc, integer], winename [varchar], winerating [varchar] and wineimage [blob].

Figure 2: Create a table
Figure 2: Create a table
Figure 3: Create the necessary columns
Figure 3: Create the necessary columns

For the sake of this tutorial, I will pre-populate the database with some wine entries and images from the web. You can add data by selecting the table and selecting the browse and data tab. To upload an image, click on the paper clip icon next to the blob field. (Figure 4 and figure 5).

Now you can close the database from the Firefox menu and Firefox as well since we won’t need anymore for the tutorial.

Figure 4: Adding a new record in the database
Figure 4: Adding a new record in the database
Figure 5: Record listing in the database
Figure 5: Record listing in the database

Create IOS 5 Project


Launch XCode 4.2 and create a Single-View IOS 5 application. Give it a meaningful name and select Storyboard and ARC. Setup your Git, or not, source control and complete the creation of your project. (figure 6).

Figure 6: The Wine List App
Figure 6: The Wine List App

Configure SQLite


Expand the Frameworks folder, right click on one of the frameworks and select Show in Finder to open Finder at the Framework location. You will need to add the libsqlite_3.0.dylib file to your project (figure 6), so move up two or three levels (see Go to Enclosing folder in the Finder menu) until you get to the usr folder. Open it and open the lib folder. Scroll down until you find the sqlite_3.0.lib. Drag the file to your Frameworks taking care to NOT copy file into the frameworks, but ONLY create a reference (Figure 7).

Next select the project root, right click and select Show in Finder. Locate your sql database you created in the first part of this tutorial and copy it into the project group where you project header and implementations files are (Figure 8).

Figure 7: Copy Reference of sqlite3.0.dylib to the Framework folder
Figure 7: Copy Reference of sqlite3.0.dylib to the Framework folder
Figure 8: Copy database file to the project folder
Figure 8: Copy database file to the project folder

Setup DAO Operations


Create a new Group (File | New Group) or from the (Context Menu | New Group). Name it “Model”. Next create two Objective-C implementation files and corresponding header files. Select the Model group and from the File menu or Context menu | select New File. Select the Objective-C node and then the Objective-C class template.

Give your file a name: WineList (if you are following this tutorial), select NSObject as the Subclass and create the file. Repeat the process for the next set of files: MyWineList, (or you can choose a name like WinesDAO). Again select the NSObject as the Subclass and create the file (Figure 9).

For the WineList class create four properties in the WineList.h (header) file, one for each column in the wineTbl (Figure 10):

  • wineId
  • wine
  • rating
  • photo


Next open the WineList.m (implementation) file to set up the getter and setter methods. So your WineList should contain four @synthesize statements, one four each property (Figure 11).

  • @synthesize wineId;
  • @synthesize wine;
  • @synthesize rating;
  • @synthesize photo;

Figure 9: Create the WineList class
Figure 9: Create the WineList class
Figure 10: Create the WineLists class
Figure 10: Create the WineLists class
Figure 11: The WineList header
Figure 11: The WineList header

Create CRUD Operations


Well CRUD is a bit of a stretch. For this tutorial it is really just a R (read) operation. Ok now the application is going to need DAO classes for the CRUD (Read) operations, so if you haven’t already done so, create a new Objective-C class: MyWineLists or whatever you want so long as the declaration and implementation works. For the MyWineLists header file, a sqlite3 object is declared and an NSMutableArray method (figure 11):

  • db
  • getMyWines



To implement these objects, open the MyWineLists.m file. In this file, the gut if the operations will take place.

To start create the NSMutableArray method getMyWines and add an array pointer variable:

  • wineArray



Next declare a NSFileManager object, a NSString object and a Bool object:

  • fileMgr
  • dbPath
  • success




NSMutableArray *wineArray = [[NSMutableArray alloc] init];
@try {
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:@"IOSDB.sqlite"];
BOOL success = [fileMgr fileExistsAtPath:dbPath];
...

The dbPath will contain to the filename and path of the SQLite database which will be passed to the fileMgr. If the file is located, success will be true. Next test to see if the file was located and if not log an error. The following operation will attempt to open the database, sqlite3_open before setting up the Select statement and sql3_stmt:

  • sql
  • sqlStatement




if(!success)
{
NSLog(@"Cannot locate database file '%@'.", dbPath);
}
if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
{
NSLog(@"An error has occured.");
}
const char *sql = "SELECT id, Wine, Rating, Photo FROM WineTbl";
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
{
NSLog(@"Problem with prepare statement");
}
...

If the database is successfully opened, the sqlite3_prepare will attempt to execute the sqlStatement. If the statement is successfully executed resulting in a result set being returned, then execute a while loop to traverse the result set assigning the values to the NSMutableArray fields.

...
while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
WineList *MyWine = [[WineList alloc]init];
MyWine.wineId = sqlite3_column_int(sqlStatement, 0);
MyWine.wine = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,1)];
MyWine.rating = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 2)];
const char *raw = sqlite3_column_blob(sqlStatement, 3);
int rawLen = sqlite3_column_bytes(sqlStatement, 3);
NSData *data = [NSData dataWithBytes:raw length:rawLen];
MyWine.photo = [[UIImage alloc] initWithData:data];
[wineArray addObject:MyWine];
}
}
@catch (NSException *exception) {
NSLog(@"An exception occured: %@", [exception reason]);
}
@finally {
return wineArray;
}

...

This pretty much takes care of the of the cRud operations. The next step will involve setting up the UI, creating IBActions and IBOutlets connections. (See figure 12, 13).

Figure 12: The implementation of WineLists
Figure 12: The implementation of WineLists
Figure 13: The CRUD operations
Figure 13: The CRUD operations

Create UI Operations



Start by locating and opening the storyboard file. You should have a single blank scene (View Controller). For this part, four labels (UILabel) are required: one for Wine Name and the value from the database and likewise for the two others: one for Wine Rating and the corresponding value from the database that will be stored in the NSMutableArray. For the images, drag an UIImageView onto the scene. As a final step for the UI, drag a UIToolbar and place it at the bottom of the screen and rename the included button: Next Bottle (Figure 14).

Figure 14: Connecting the dots
Figure 14: Connecting the dots
Figure 15: The project structure
Figure 15: The project structure

To finish off the app, some code needs to be added to the ViewController header and implementation files. So to setup the IBAction and IBOutlet, open the header file alongside the storyboard by clicking on the Assistant Editor, the face icon in the Toolbar (Figure 14). Start by selecting the first label and dragging a connection line (Ctrl+left mouse button) to the header file between the last curly brace and the @end directive. In the Popup, select IBOutlet and enter a name like: winename. Continue with second label that will contain the rating information. This will also be an IBOutlet and the name will be: winerating. For the image, repeat the same operation as the two preceding ones. This connection will also be an IBOutlet and the name will be : wineViewer. Finally drag a connection line from the button in the Toolbar. This will be an IBAction and the name of the method: GetWineListing. Also add a NSMutableArray object:

  • wines



You should have little filled in dot in the margin indicating that connections have been made.

Next open the implementation file. Setup the getter and setters:


@synthesize wineViewer;
@synthesize winename;
@synthesize winerating;
@synthesize wines;



In the viewDidLoad, which is called when the app is finished initializing itself, add pointers to hold the initial data in the array so the app will display some information and image that is located at index 0.


- (void)viewDidLoad
{
MyWineLists * mywines =[[MyWineLists alloc] init];
self.wines = [mywines getMyWines];
[self.wineViewer setImage:((WineList *) [self.wines objectAtIndex:0]).photo];
[self.winename setText:((WineList *) [self.wines objectAtIndex:0]).wine];

[self.winerating setText:((WineList *) [self.wines objectAtIndex:0]).rating];

[super viewDidLoad];
}
...

in the viewDidUnload set your properties to nil to release them from memory


- (void)viewDidUnload
{
[self setWineViewer:nil];
[self setWinename:nil];
[self setWinerating:nil];
[super viewDidUnload];
}
...

Finally implement the GetWineListing method, so when the user clicks on the button, the index gets incremented and retrieves the data at the selected index number.


- (IBAction)GetWineListing:(id)sender {
static NSInteger currentIndex = 0;
if (++currentIndex == [self.wines count]) {
currentIndex=0;

}else{
WineList *aWine = (WineList *) [self.wines objectAtIndex: currentIndex];
[self.winename setText:aWine.wine];
[self.winerating setText:aWine.rating];
[self.wineViewer setImage:aWine.photo];
}
}

Test Your App



Ok, we are done. Click on the Run button to launch your app. After the app is finished initializing you should have from data and image on screen. Click the Next Bottle to get the next listing.

Figure 15: The running app
Figure 15: The running app

Source Code



Here is the complete source code of the various files that were created.

WineList.m

//
//  WineList.m
//  MyWineList
//
//  Created by Kevin Languedoc on 11/25/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import "WineList.h"

@implementation WineList
@synthesize wineId;
@synthesize wine;
@synthesize rating;
@synthesize photo;

//With ARC, if you selected id, you don't need to dealloc

@end

MyWineLists

//
//  MyWineLists.h
//  MyWineList
//
//  Created by Kevin Languedoc on 11/25/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <sqlite3.h>

@interface MyWineLists : NSObject{
    sqlite3 *db;
}

- (NSMutableArray *) getMyWines;

@end

WineList.h

//
//  WineList.h
//  MyWineList
//
//  Created by Kevin Languedoc on 11/25/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface WineList : NSObject{
    NSInteger wineId;
    NSString *wine;
    NSString *rating;
    UIImage *photo;
}

@property (nonatomic,retain)NSString *wine;
@property (nonatomic, assign) NSInteger wineId;
@property (nonatomic, retain)NSString *rating;
@property (nonatomic, retain) UIImage *photo;


@end

MyWineLists.m

//
//  MyWineLists.m
//  MyWineList
//
//  Created by Kevin Languedoc on 11/25/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import "MyWineLists.h"
#import "WineList.h"

@implementation MyWineLists
- (NSMutableArray *) getMyWines{
    NSMutableArray *wineArray = [[NSMutableArray alloc] init];
    @try {
        NSFileManager *fileMgr = [NSFileManager defaultManager];
        NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:@"IOSDB.sqlite"];
        BOOL success = [fileMgr fileExistsAtPath:dbPath];
        if(!success)
        {
            NSLog(@"Cannot locate database file '%@'.", dbPath);
        }
        if(!(sqlite3_open([dbPath UTF8String], &db) == SQLITE_OK))
           {
               NSLog(@"An error has occured.");
           }
        const char *sql = "SELECT id, Wine, Rating, Photo FROM  WineTbl";
        sqlite3_stmt *sqlStatement;
        if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
           {
               NSLog(@"Problem with prepare statement");
           }
        
        //
        while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
            WineList *MyWine = [[WineList alloc]init];
            MyWine.wineId = sqlite3_column_int(sqlStatement, 0);
            MyWine.wine = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,1)];
            MyWine.rating = [NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement, 2)];
            const char *raw = sqlite3_column_blob(sqlStatement, 3);
            int rawLen = sqlite3_column_bytes(sqlStatement, 3);
            NSData *data = [NSData dataWithBytes:raw length:rawLen];
            MyWine.photo = [[UIImage alloc] initWithData:data];
            [wineArray addObject:MyWine];
        }
    }
    @catch (NSException *exception) {
        NSLog(@"An exception occured: %@", [exception reason]);
    }
    @finally {
        return wineArray;
    } 
    
    
}


@end

kcbViewController

//
//  kcbViewController.h
//  MyWineList
//
//  Created by Kevin Languedoc on 11/25/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface kcbViewController : UIViewController{
    NSMutableArray *wines;

    
}

@property(nonatomic,retain) NSMutableArray *wines;
@property (weak, nonatomic) IBOutlet UIImageView *wineViewer;
@property (weak, nonatomic) IBOutlet UILabel *winename;
@property (weak, nonatomic) IBOutlet UILabel *winerating;
- (IBAction)GetWineListing:(id)sender;


@end

kcbViewController.m

//
//  kcbViewController.m
//  MyWineList
//
//  Created by Kevin Languedoc on 11/25/11.
//  Copyright (c) 2011 kCodebook. All rights reserved.
//
#import "kcbViewController.h"
#import "WineList.h"
#import "MyWineLists.h"

@implementation kcbViewController
@synthesize wineViewer;
@synthesize winename;
@synthesize winerating;
@synthesize wines;


- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle

- (void)viewDidLoad
{
    MyWineLists * mywines =[[MyWineLists alloc] init];
    self.wines = [mywines getMyWines];
    [self.wineViewer setImage:((WineList *) [self.wines objectAtIndex:0]).photo];
    [self.winename setText:((WineList *) [self.wines objectAtIndex:0]).wine];
    
    [self.winerating setText:((WineList *) [self.wines objectAtIndex:0]).rating];
     
    [super viewDidLoad];
}

- (void)viewDidUnload
{
    [self setWineViewer:nil];
    [self setWinename:nil];
    [self setWinerating:nil];
    [super viewDidUnload];
}

- (IBAction)GetWineListing:(id)sender {
    static NSInteger currentIndex = 0;
    if (++currentIndex == [self.wines count]) {
        currentIndex=0;
}else{
        WineList *aWine = (WineList *) [self.wines objectAtIndex: currentIndex];
        [self.winename setText:aWine.wine];
        [self.winerating setText:aWine.rating];
        [self.wineViewer setImage:aWine.photo];
    }
}

- (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);
}




@end
Build iOS Database Apps with Swift and SQLite
Build iOS Database Apps with Swift and SQLite

If you would like more information on developing iOS database Apps, check out my new book "Build Database Apps using Swift and SQLite which is published by Apress

 

In summary



That pretty wraps it up. In the hindsight, implementing SQLite was very easy. The only thing missing is the operations to create records, updating and deleting them. That as they say is another story, or article in this case. If you need to know how to perform inserts, updates and deletes, check out my article: IOS 5 SDK Database: Insert, Update, Delete with SQLite and Objective-C | C | How-To

Another useful tutorial is : Tutorial on How to Display & Write SQLite Data in Table View Controller & Detail View Controller | iOS 5 App

Comments

    0 of 8192 characters used
    Post Comment

    • profile image

      Pan Sabalhs 2 months ago

      Dear Kevin . In wines example i want to add , insert , update records. I shaw the link example you suggested but i could'nt go on i stuck. Because i i made a books database taken as example the wines one can you help me with a little bit code ?

      PS: In Books database i made a master detail tableview and i want from detail view add, edit records and affect main tableview.

      MANY THANKS AND I AM WAITING .......

    • profile image

      Pan Sabalhs 5 months ago

      Hello Kevin , in the wines tutorial can you give me an example how to add/edit a wine image ? Where the new images are stored ( in the beginning of course are in assets) ?

      I am confused about asset library and photo gallery. In iphone are the same ? Please answer me , because I want to make a similar database for my books and I ' ve stuck. Many hanks and I wait your answer.

    • shahpratik profile image

      Pratik Shah 6 months ago from Mumbai

      Hi Kevin,

      Its been quite some time since I visited here last. After purchasing your ebook and with the help of some other online tutorials I somehow managed to get a functional app with sqlite database.

      But now I am little stuck with the end part of the app; I am trying to add sections and index for the uitableview. Do you have any tutorial for it or can you share some insight on how can I get working;

      Most of my code has been taken from your source code you have supplied.

      Thanks in advance.

    • profile image

      Pan Sabalhs 7 months ago

      Hello again .I have a .db database for my books. The cover of my books is in assets as .png file. How can I download all the images from assets to photo library ? Can you post a code example please?

      Many thanks !

    • profile image

      Pan Sabalhs 7 months ago

      Hello again.I made a books.db database with 3 tables tblAuthor , tblTitle,tblPublisher.In a view controller I've put a tableview controller , a navigation bar and a toolbar with 3 items ''Authors" , "Title" , "Publisher".I connected the view controller with database.All that I want is to populate the same table with different sql queries , pressing the corresponding tool bar items.For example when I press the "Authors" populate the table with sql select * from tblAuthor , pressing "Title" item (erase previous data from table) and populate the same table with sql select *title from tblTitle and so on.Can you help me please with a little bit code or a similar tutorial.This will help to go on my project.MANY THANKS !!

    • klanguedoc profile image
      Author

      Kevin Languedoc 7 months ago from Canada

      Hi

      Pan Sabalhs

      Adda variable to the object that contains the data for the thebooks and add a label to the ui uitableviewcell and displays the result

    • profile image

      Pan Sabalhs 8 months ago

      Hello , congratulations for all those tutorials !

      I have a question.I want above the searchbar to write the results from filtered records from a book database.Suppose for the books the NSMutablearray is thebooks and for filtered books is the NSMutablearray filtbooks.I want the title to be like this : I found filtbooks from thebooks.I know that shall I use the count command but where and how shall I put the title.

      Many thanks

    • klanguedoc profile image
      Author

      Kevin Languedoc 8 months ago from Canada

    • profile image

      Pan Sabalhs 8 months ago

      Hello again , first congratulations for your tutorials , are very helpfull ! Based on your tutorials I made a database for my books with a tableview.Is there any idea how putting some suitable buttons in toolbar to to go ( scroll) to first ,next previous and last cell ? Is very critical for me because database has already 100 records and you understand that is difficult to scroll on ipad or iphone to 100th record. Many thanks , I wait your answer.

    • profile image

      Pan Sabalhs 9 months ago

      Hello , in previous question with ID , I solved it many thanks. I want in the above tutorial to add a code for last bottle. I use this and I have errors :

       (IBAction)Last:(id)sender {

      // i put currentIndex = 0 in viewdidload and is declared in header and property as nsinteger;

      currentIndex = [self.wines count];

      WineList *aWine = (WineList *) [self.wines objectAtIndex: currentIndex];

      [self.winename setText:aWine.wine];

      [self.winerating setText:aWine.rating];

      [self.wineViewer setImage:aWine.photo];

      }

      Many thanks !

    • profile image

      Pan Sabalhs 9 months ago

      Hello , can you tell me please if I want in above tutorial to see the Id before wine name as A/A, how can I do this? I tried setText with stringwithformat but no result.Thanks in advanced.

    • klanguedoc profile image
      Author

      Kevin Languedoc 9 months ago from Canada

      Hi Pan

      I dont know fmdb so i cant help you out. For the wineid i guess add a field or label in cancas then create iboutlet in viewcontroller then folllow code example as other field to map

    • profile image

      Pan Sabalhs 9 months ago

      Hello , if I want to display the wineId in viewcontroller what code shall I write ?

    • profile image

      Pan Sabalhs 9 months ago

      Hello , it's a great example.I can't see the code kcbAppDelegate.Can you tell me what changes shall i make in the code to support FMDB and .db database?

    • klanguedoc profile image
      Author

      Kevin Languedoc 2 years ago from Canada

      Segovia

      Only if you create a web based RESTful web service connected to a database like mongodb for instance or a RBMS like MySQL.

      Emmanuel

      Glad you figured it out

      Harbi

      Thanks for the feedback. I am glad the tutorial was helpful

    • profile image

      M. Harbi 2 years ago

      Thanks a lot for this tutorial...

    • profile image

      Segovia 2 years ago

      If I create this app and put it in AppStore, could all the users connect to the same database?

      It might be a silly question but I am really new to iOS.

    • profile image

      Emmanuel 2 years ago

      Thanks a lot for this tutorial it solved a problem I have battling with for nearly two weeks

    • klanguedoc profile image
      Author

      Kevin Languedoc 2 years ago from Canada

      Are you getting an error message?

      Are you initializing the sqlite object?

    • profile image

      sam 2 years ago

      i m new to ios

      i want to establish connection b/w xcode and sqlite db.

      but i m nt getting connected

    • shahpratik profile image

      Pratik Shah 2 years ago from Mumbai

      Hello Kevin,

      Thanks for the link. I did download the files. But unfortunately, I am not getting the filtered results on my second table view, instead I get blank tableview.

      Will keep trying as I learn to xcode :).

      Many thanks.

    • klanguedoc profile image
      Author

      Kevin Languedoc 2 years ago from Canada

      you can download the FirstTableProject here:

      https://github.com/kevlangdo/iosdev101

    • klanguedoc profile image
      Author

      Kevin Languedoc 2 years ago from Canada

      shahpratik please send me an e-mail and I will send you the FirstTableProject directly to you.

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      I will check. Sorry about that

    • shahpratik profile image

      Pratik Shah 3 years ago from Mumbai

      Hello Kevin,

      Thanks for your efforts. I tried downloading the file, but it seems the link to FirstTableProject.zip is not working. Can you please check if the link is working at your end.

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      First download the FirtsTableProject from the iosdev101.com/downloads web site

      For both TableViwControllers, add the TableViewController delegate and DataSource proxies

      in the designer by dragging a connection from the view to the proxy icon at the top

      of the scene in the IB and select data source and then delegate. Do this for for both

      TableViewControllers.

      Next create a segue from table 1 to table 2 and name the segue showStates or something

      like this. Create a segue from table 2 to detail controller as well and name it in

      attributes.

      Add the TableViewController delegate and data source protocols to header files of

      TableVirewController

      1) First TableViewController

      header

      #import "CountryStates.h"

      #import "StateTableViewController.h"

      @interface TableViewController : UITableViewController[angle bracket]UITableViewDelegate,UITableViewDataSource[angle bracket]

      @property(nonatomic, strong) CountryStates * cs;

      @property(nonatomic, strong) NSMutableArray * countryList;

      @property(nonatomic, strong) StateTableViewController * statesv;

      @property(nonatomic, readwrite)NSInteger rowNbr ;

      @end

      implementation

      - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

      // Get the new view controller using [segue destinationViewController].

      // Pass the selected object to the new view controller.

      if([[segue identifier] isEqualToString:@"showStates"]){

      NSIndexPath *selectedIndexPath = [self.tableView indexPathForSelectedRow];

      statesv = [segue destinationViewController];

      //This is our data source that we are passing to the second TableViewController

      statesv.stateList = [[NSMutableArray alloc] initWithArray:(NSArray*)countryList];

      //We are passing the selected country to the second TableViewcontroller

      statesv.states = [self.countryList objectAtIndex:selectedIndexPath.row];

      }

      }

      2- Second TableViewController

      header:

      #import "CountryStates.h"

      @interface StateTableViewController : UITableViewController

      @property(nonatomic, strong) CountryStates * states;

      @property(nonatomic, strong) NSMutableArray * stateList;

      @property(nonatomic, strong) NSArray *filterValue;

      @end

      implementation:

      @implementation StateTableViewController

      @synthesize states,stateList, filterValue;

      - (void)viewDidLoad {

      [super viewDidLoad];

      //we need to de-reference the passed value

      states = (CountryStates*)self.states;

      stateList = (NSMutableArray*)self.stateList;

      // Uncomment the following line to preserve selection between presentations.

      self.clearsSelectionOnViewWillAppear = YES;

      NSPredicate * predicate = [NSPredicate predicateWithFormat:@"country contains %@",states.countryName];

      filterValue = [self.stateList filteredArrayUsingPredicate:predicate];

      }

      Setup the tableView methods like in sample app FirstTableProject. FilterValue is the new data source

      with the filtered list of states.

      For the prepareForSeque in second TableViewcontroller, use the sample code from the FirstTableProject

      to transfer selected value to detailViewController.

    • shahpratik profile image

      Pratik Shah 3 years ago from Mumbai

      Never mind. At your convenience please. Many thanks.

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      Sorry for the delay. I am working on it but I am on the tail end of a project and it is taking a lot of my time. Please give a few more days.

    • shahpratik profile image

      Pratik Shah 3 years ago from Mumbai

      Hello Kevin,

      Sorry to bother you again, but by any chance do you have any step-by-step tutorial to add sections in uitableview that loads data from sqlite like in this same wine tutorial?

      I am trying to create section titles with country names and in that section will populate list of states for that country and clicking on state would bring up detail view of state. This will eliminate one extra view altogether.

      Many thanks in advance.

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      Hi shahpratik

      I will put together some code for you to rudiment-ally illustrate what I mean.

      Kevin

    • shahpratik profile image

      Pratik Shah 3 years ago from Mumbai

      Hi Kevin,

      Thanks for your reply.

      I am still struggling to get this working. Kindly suggest at your convenience.

      Many thanks.

      Pratik

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      In your first tableviewcontroller, you need to implement a db search like :

      https://hubpages.com/technology/Develop-a-UISearch...

      When you return the search results, store this in a new NSMutableArray and pass this to the next using the id object which will be the dataset for the second tableviewcontroller. You transfer the array the same way as the detailvewcontroller. Then on the second tableviewcontroller, you can do another select and display the state information in a detailviewcontroller.

      If you are stuck, let me know and I will write some code for you.

      Kevin

    • shahpratik profile image

      Pratik Shah 3 years ago from Mumbai

      I have been following this tutorial of yours and have been successful in taking it forward with search bar implementation & TabBar interface.

      However, I am stuck at one point if you can refer to some similar tutorial or guide on how to get it working...

      Instead of present logic that displays sqlite data in first tableview and than on select, show detailview, I need something like this...

      Load sqlite data in first TableView, than on selection, filter data to another tableview and then finally on select, show detail view.

      For e.g. in first tableview I load list of countries from sqlite, when I select a country, it loads list of states for that country in second tableview and than finally when I select a state, it shows details view of that state.

      Thanks in advance.

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      I am glad I was able to help...

    • profile image

      farmNXT 3 years ago

      Very nice and helpful article..!

      http://www.farmnxt.com/

    • profile image

      Mannan1994 3 years ago

      Ohh okay ! one last question , I have an database in .sqlite format , which contains more than 2000 rows in it , so I want my program to print all the text in an textview which is in its last column of database (by appending the previous string )

      and is there any way to print a arabic text file in our app through UITextView, when I tried to print it gets an error in console and my app stucks

      Thanks !

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      Hi Mannan1994

      Thanks fort the kind words. Aways appreciated :)

      SQLite is strictly a local database engine, meaning that you can't use on a network or a web site unless that web site is standalone. If you develop a mobile app, a desktop app either using native programming languages or web technology, you can use SQLite.

    • profile image

      Mannan1994 3 years ago

      Hey klanguedoc ! this tutorial was awesome thanks for this tutorial .. :D

      I want to ask a simple question ,as in this tutorial we have taken the .sqlite file from our computer, how to get that file through the website or network

      Thanks

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      yes, you can download the code from www.iosdev101.com

      Thanks

    • profile image

      umr 3 years ago

      hello,

      thank you for tutorial. can i use some part of your code in my app?

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      Hi Joe,

      In theory, you can use all the available space on the iPad HDD. SQLite is a powerful database and can easily handle a 1 GB of data. As you mentioned, the table structures and index are very important in SQlite like in any database. I would start there, even testing your database outside of the iPad app using the SQLite CLI (CommandLine) to see if the issue is actually SQLite or the design of the app itself.

      Please let me know if you need more info or help

      Cheers

      Kevin

    • profile image

      Joe Morgan 3 years ago

      How much data can an iPad onboard SQLite database handle (Not web served)? I know that's a bit like asking how long is a piece of string but our developer is saying the queries are too large for the db to handle and slows down or returns unreliable data.

      I have a feeling that it's the way they've structured it, such as poorly built tables, indexes and queries.

      Any thoughts?

      Cheers Joe

    • klanguedoc profile image
      Author

      Kevin Languedoc 3 years ago from Canada

      ThienHaoLe

      All code can dowmloaded from my site : www.iosdev101.com

      jd

      you can create a method with a bool return value

      in header

      -(bool)checkPassword:(NSString *)input;

      implementation

      -(bool)checkPassword:(NSString *)inputValue{

      bool passwordOk = true;

      // do a simple select using similar as in example code above and other sample in my other tutorials. If the value matches inputValue, return passwordOk as is, otherwise set passwordOk = false

      return passwordFalse;

      }

    • profile image

      jd 3 years ago

      it working good love u kevin

      and i have one problem can u help me in my aplllication how we can match textfeild value with sqlite field value something like password field when user input wrong pass then alert them by wrong password please help me i am beginner in iphone developing

    • profile image

      ThienHaoLe 3 years ago

      can you sent me your code?

      my email : thienhaole92@gmail.com

    • profile image

      Jason 3 years ago

      Its working thanks. I think, you does not need to write else{} in "- (IBAction)GetWineListing:(id)sender {

      static NSInteger currentIndex = 0;

      if (++currentIndex == [self.wines count]) {

      currentIndex=0;

      }else{

      WineList *aWine = (WineList *) [self.wines objectAtIndex: currentIndex];

      [self.winename setText:aWine.wine];

      [self.winerating setText:aWine.rating];

      [self.wineViewer setImage:aWine.photo];

      }

      }"

      Instead :-"- (IBAction)GetWineListing:(id)sender {

      static NSInteger currentIndex = 0;

      if (++currentIndex == [self.wines count]) {

      currentIndex=0;

      }

      WineList *aWine = (WineList *) [self.wines objectAtIndex: currentIndex];

      [self.winename setText:aWine.wine];

      [self.winerating setText:aWine.rating];

      [self.wineViewer setImage:aWine.photo];

      }" .

    • profile image

      hahahahah 3 years ago

      lol :)-

    • profile image

      jd 4 years ago

      when i click on next button it doesn't work and i have msg Application windows are expected to have a root view controller at the end of application launch plz help me out

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      You have a typo in your query string

    • profile image

      AMAN 4 years ago

      if(sqlite3_prepare(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)

      {

      NSLog(@"Problem with prepare statement");

      }

      It print only "Problem with prepare statement".

      How can i solve this...?

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Hi Vijayendra,

      You can cast the UILabel to the id like (UILabel *) id. then you can use the UILabel properties and attributes.

      Karthi

      You can download the code from www.iosdev101.com

    • profile image

      karthi 4 years ago

      I stored images in my server. But images are not fetching from database. Can you give me some link?

    • profile image

      vijayendra 4 years ago

      How to set Id with integer value and date with varchar in viewdidload?

    • profile image

      vijaynedra 4 years ago

      Nice tutorial I have one question h0w to set id into label?

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Great I am glad you figured it out.

    • Russell Crow profile image

      Russell Crow 4 years ago from Flower Mound, Texas

      I built this and got the same error

      "Problem with prepare statement" and the follow up crash which looks like *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 1 beyond bounds for empty array'

      So I found my problem, it is the SELECT STATEMENT doesn't match the DATABASE COLUMNS. The 4 items you call in the statement have to match the columns in your database EXACTLY, otherwise the sqlite_prepare statement will fail.

      The following statement works:

      const char *sql = "SELECT id, winename, winerating, wineimage from WineTbl";

      IF AND ONLY IF the columns in your IOSDB.sqlite database are:

      id winename winerating wineimage

      ANY variance in ANY name causes a problem. Also, if you named this table WineTbi or winetable or anything else, it will fail.

      That's the problem with computers, they do exactly what you tell them to.

      Many thanks to Klanguedoc! This is one of the most straightforward iOS SQLITE tutorials on the web.

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Thanks

    • profile image

      Jung-su Kim 4 years ago

      Thank you for your good tutorial!

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Junior Programmer,

      I was referring to the SQLite Mgr in Firefox

      milon,

      is the sqlite library properly added to the frameworks?

    • profile image

      milon 4 years ago

      The following error arise when i build my project where is the problem can anyone explain plz......

      Undefined symbols for architecture i386:

      "_sqlite3_column_int", referenced from:

      -[DBList getUser] in DBList.o

      "_sqlite3_column_text", referenced from:

      -[DBList getUser] in DBList.o

      "_sqlite3_open", referenced from:

      -[DBList getUser] in DBList.o

      "_sqlite3_prepare", referenced from:

      -[DBList getUser] in DBList.o

      "_sqlite3_step", referenced from:

      -[DBList getUser] in DBList.o

      ld: symbol(s) not found for architecture i386

      clang: error: linker command failed with exit code 1 (use -v to see invocation)

    • profile image

      Junior Programmer 4 years ago

      Hi thanks for this tutorial. However i'm getting an error while doing so. Also you have said "Now you can close the database from the Firefox menu and Firefox as well since we won’t need anymore for the tutorial".

      How am i suppose to read your tutorial and work it out then ? :P

    • profile image

      Almas 4 years ago

      Hi everyone. I had the same issue with "problem with prepare statement". I fixed it by adding my database file into "target - build phases - copy bundle resources".

      I hope that helps..

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Hi IMx,

      If the table maintains the original columns and data types, yes your data will be maintained. If you remove the original columns, you will need some kind of script to migrate the data already in the database. In other words you can change the schema as muh as you want as long as the original columns are maintained otherwise you will get errors or lost of data

    • profile image

      iMx 4 years ago

      Thanks for this tutorial!

      I want to extend the LegaultMD's question: assuming an user adds some entries in a table, and than I want to change the structure of this table. Will this overwrite the users data if the user installs the new version of the app (because he gets a new sqlite file with my entries)?

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Hi LegaultMD,

      If you are updating your database, all you need to change the db file and update the code if you change the database schema.

      Kevin

    • profile image

      LegaultMD 4 years ago

      Great tutorial! I just have one question.

      If I want to change my database, or add more entries in it, do I have to do this entire process again? Or I just add the necessary lines of code?

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Hi bkasmai,

      Sorry for the late reply. I would say that your view controller kcbViewController is not properly setup in the Storyboard. Or is this class added to the corresponding view controller in the Storyboard (see custom class in identity inspector). Thanks for kind words.

    • profile image

      bkasmai 4 years ago

      Hi klanguedoc

      This is one of the best tutorial on iOs+sqlite i have come across. I would be really grateful if you could please shed some light on the error below. I am really struggling to get to the bottom of this as I have checked the code on GetWineLising over and over again without much luck.

      *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[kcbViewController 0x748d530 setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key GetWineListing. '

      PS I have to remove inequality signs from the error message to make the posting possible

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

    • profile image

      ty 4 years ago

      hey klanguedoc,

      Thank you so much for the tutorial. I followed any other tutorial on sqlite but none of them worked. so, i would like to know if you have another tutorial where database creation is hardcoded instead of creating it at some other place first? because those are the tutorials i've tried so far and always failed.

      Thanks once again.

      Cheers!

      Ty

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Wow AramDiv. Thank you very much.

    • profile image

      AramDIV 4 years ago

      Hello klanguedoc .. I just want to say many thanks to you ... YOU ARE BRILLIANT TEACHER !

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      thanks for your kind words however I don't have any code or tutorials on APN at the moment

    • profile image

      Appdev 4 years ago

      Thank you for the fantastic tutorial ! Do you have any related to Push Application that use APNs?

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      HI SPT,

      I am glad the tuts have help you out. What I do in the production environment is create a backup directory in the Library directory. I then make a copy of the current database in this directory before upgrading or replacing the current database. Once the database is upgraded or replaced, I then move the data back using SQL or update the data as needed.

      Once thing you mentioned that you need to manage is backups since SQLite databases can grow very large over time and you will need to backup strategy.

      Here I use two different strategies, sometimes I provide a means to let the user backup his or hers data to iCloud, Dropbox or a corporate network or computer, otherwise I simply make a copy of the database to one of the abovementioned places.

      Hope this helps

      Kevin

    • profile image

      SPT 4 years ago

      Hello Kevin,

      Thank you so much for posting the tutorials, I greatly appreciate. I went through both of the Tutorials on SQLITE and they both helped me a lot... Since I am very GREEN in programming and SQLITE is completely new subject, I have a question that had been on my mind since I started learning SQLITE and if you could help me with my Paranoia or point me in the right direction I would greatly appreciate it (my apology if this was already asked by someone). Let me explain the Scenario here:

      1. Let's say I post an APP, that saves everything into the DB, in the STORE today.

      2. The Customer that downloads APP will use the APP for a while, which will cause for him/her to have lots of Data Saved in the DB.

      3. Let's say, after a while I need to make updates to the APP.

      The question is, how can I Prevent the loss of data in the DB that the customer saved for a while? Please let me know.

      Thank you,

      SPT

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Great I'm happy :)

      Kevin

    • profile image

      Iva 4 years ago

      Kevin,

      thank you, it helped me again!!! :)

      Iva

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Hi Iva,

      Yes it is possible. After defining a segue from the button to the other view controller and adding the button t the view controller proxy at the bottom of the scene where the button is located, add a prepareForSegue method to the implementation file in the prepareForSegue method get the row index from either the array using the objectAtIndex and then follow my other tutorials to send the data to the view controller.

      Also UITableViewDelegate has a method – tableView:didSelectRowAtIndexPath: that will retrieve the row selected which can be added to a variable so when the you clicks on the button will send the selected object to the next view controller. You will need to add the protocol to the header file and add the delegate to the scene proxy.

      Hope this helps

      Kevin

    • profile image

      Iva 4 years ago

      Dear Kevin,

      I have one more question... :)

      Is it possible to make -IBAction GetWineListing method, that when the user clicks on this button next wine will be shown in another View Controller?

      Finally implement the GetWineListing method, so when the user clicks on the button, the index gets incremented and retrieves the data at the selected index number.

      - (IBAction)GetWineListing:(id)sender {

      static NSInteger currentIndex = 0;

      if (++currentIndex == [self.wines count]) {

      currentIndex=0;

      }else{

      WineList *aWine = (WineList *) [self.wines objectAtIndex: currentIndex];

      [self.winename setText:aWine.wine];

      [self.winerating setText:aWine.rating];

      [self.wineViewer setImage:aWine.photo];

      }

      }

      This functions only in the same View Controller...

      Thank you very very much for your help!!!

      Iva

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      glad to help

    • profile image

      Iva 4 years ago

      Thank you very much:)

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      It is here

      NSString *dbPath = [[[NSBundle mainBundle] resourcePath ]stringByAppendingPathComponent:@"IOSDB.sqlite"];

      iva,

      in the method where you want to set the number to the label do this (you should not have a instance variable preis and a UILabel preis

      preis.text = [preis stringValue];

    • profile image

      tinkerer 4 years ago

      hi,

      Where in the code do you specify the path to database? I am trying to change the database, but somehow the simulator keeps showing me the original database.

      I simply want to replace the old database with new one.

    • profile image

      Iva 4 years ago

      Hallo klanguedoc,

      thank you very much for your answer. I´m a newbie and I don´t know what to do exactly.

      I made now i SQLite Manager a new field price - REAL,

      Than in WineList.h - NSNumber *preis; and @property (nonatomic, retain) NSNumber *preis;

      kcbViewController.h - @property (weak, nonatomic) IBOutlet UILabel *preis;

      But now I don´t know what to do in kcbViewController.m.

      Can you please help me once again?

    • klanguedoc profile image
      Author

      Kevin Languedoc 4 years ago from Canada

      Iva

      You need to use the NSNumber instead of double and the stringValue property.

    • profile image

      omid 4 years ago

      hi klanguedoc ... first of all i want to thank you for this great tutorial...

      i have 1 confusion since i just started out working with objective c... after i create the database and the table inside the Sqlite manager, do i need to export it and drag it to my project? if yes why is the extension .sql not .sqlite when i export it? thanks in advance ...

    • klanguedoc profile image
      Author

      Kevin Languedoc 5 years ago from Canada

      The database has to be in the Documents directory. In this tutorial it is in the Resource folder which is read-only. The Documents folder is read-write.

    • profile image

      srihot 5 years ago

      Error:

      2012-10-14 12:58:55.882 AppName[1842:907] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error: failed to insert into the database with message 'attempt to write a readonly database'.'

    • profile image

      srihot 5 years ago

      Dear Kevin,

      I ran the app on iPad . It was running in simulator with out any problem.

      But when I ran this app on iPad , Find fetching records , but update is not working,

      Is there any special access required for write to database. I created DB and table as you explained in the above

    • klanguedoc profile image
      Author

      Kevin Languedoc 5 years ago from Canada

      Thanks Haider Ali, does your NSMutableArray contain all the records in the database?

    • profile image

      Haider Ali 5 years ago

      Very good tutorial for the newcomer in iPhone, but i have a problem, i have followed each and every instructions u made in ur tutorial but i put the records more than two in the sqlite db,and run my app, i just watch the first two,how can i see the all records in my app on next bottal button click

      Thanks a lot Sir,

      waiting for ur reply

    • klanguedoc profile image
      Author

      Kevin Languedoc 5 years ago from Canada

      Hi srihot,

      Please take a look at this tutorial I wrote. It demonstrates how to update records in a SQLite database.

      https://hubpages.com/technology/IOS-5-SDK-Database...

    • profile image

      srihot 5 years ago

      Thanks Kevin,

      Could please make sure It should have model group with 4 classes and Update button code in the viewcontroler.m

    • klanguedoc profile image
      Author

      Kevin Languedoc 5 years ago from Canada

      Hi srihot,

      I will post later today.

    • profile image

      srihot 5 years ago

      Hi,

      I created a prototype app using this code and working, But last minute , I have to update few of these fetched records. Can you please guide me,

      I created a new App for Find a record and update the same and Insert a new record. All these are working.

      BUT I want to use the above code and update method also

      Can you please help me. Thanks in advance

    • klanguedoc profile image
      Author

      Kevin Languedoc 5 years ago from Canada

      Thanks for the great feedback.

      Hi tinkerer,

      I haven't done any testing so far with iOS 6. I will check out the image browsing issue and post an update if needed.

      Hi Lu,

      I don't have a tutorial for off device databases. But what i have done in the past is use the NSURLConnection which can handle asynchronous connections like web services and Ajax to interface with a web service on a network database. I could prepare a little tutorial if you want.

      Hi slad,

      Thanks also. You can either use multiple databases with a single table or create multiple tables in a single database. The is simple, in the example below, instead of creating one table, just have three create table queries and execute them. To write a select, it is standard SQL: use an inner join on the table like any other SQL statement.

      char *emsg;

      BOOL fileExist;

      //Get list of directories in Document path

      NSArray * dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

      //Define new path for database in the documents directory because data cannot be written in the resource folder.

      NSString * documentPath = [[dirPath objectAtIndex:0] stringByAppendingPathComponent:@"binaryDb.db"];

      fileExist = [[NSFileManager alloc] fileExistsAtPath:documentPath];

      if(fileExist){

      if(!(sqlite3_open([documentPath UTF8String], &db) == SQLITE_OK))

      {

      NSLog(@"An error has occured.");

      }else{

      const char *sqlTable = "create table if not exists binaryTbl(fileName varchar, binaryData blob)";

      if(sqlite3_exec(db, sqlTable, NULL, NULL, &emsg) != SQLITE_OK)

      {

      NSLog(@"There is a problem with statement");

      }

      }

      }

    • profile image

      siad 5 years ago

      Hi , thanks for all the tutorials

      Can you make a tutorial with SQlite database. I want to Select and Insert data from three tables, not only one tables

      Can please guide me this?

    • profile image

      lu 5 years ago

      Hi,

      This is a really great tutoril, but it only stores data in the phone.

      what if the database gets larger, how can I put the data base in a different server and still access it? Do you have a tutorial for that?

    • profile image

      tinkerer 5 years ago

      I didn't get storyboard connections to work; so re-did the whole app from scratch and it worked well. I just tested in iOS6 iPad simulator, seems to work ok, except the 1st image is not getting repeated after flashing once, as I do next/next/next. I am trying to figure it out,

      a great tutorial overall, thanks.