Store Binary Data in an iPhone SQLite Database App

Source

(c) 2012 kevin languedoc (klanguedoc)

Learn how to store binary data in a SQLite database with this iPhone tutorial. Learn convert an image to a binary format using NSData and to insert that NSData in a SQLite data base. This tutorial also shows how to use iOS development to display a list of image files in an UITableView and UIPickerView and to display the stored binary from the database and display the image in an UIImageView.

project overview
This app when launched will display a list of jpg images that are stored in the Resource folder of the project in a TableView. When a user, you, clicks on a filename, that file will be converted to binary data (NSData) and will be inserted in a SQLite database that was dynamically created in the AppDelegate’s didFinishWithOptions method.

When the user selects the view tab of the TabbedViewController, the scene presents a list of filenames in an UIPickerView from the SQLite database. When the the user selects an item from the UIPickerView, the corresponding binary data is retrieved from the database, converted to an UIImage object and displayed in an UIImageView control.

Running iPhone App

In the a production application, it is not recommended to store large quantities of binary data in a SQLite or any other database. It is a waste of resources, but it is ok to store a limited amount of binary data if your app needs this functionality. It is far better to simply store the filenames or other key attributes in the database and the actuals on the file system. This app and tutorial is for demonstration purposes.

Project Setup

To build this project, I used a Single View Controller project from the available templates. Since this project will require a different configuration than the original Single View, I will delete the view controller class that was created by default when the project was created. To replace this view controller, I will create two new ones as well as a custom class, BinaryDAO as a subclass of the NSObject class. I cover this process in the following sections.

Before I can start adding the new subclasses, I will add the sqlite3 library to the project. Select the project root in the Project Explorer. Select the Summary page and scroll down the “Linked Frameworks and Libraries” section. Click on the “+” button and enter sqlite3 in the search field. Select the “libsqlite3.0.dylib” library file and click the “Add” to add the library to the project. Next drag the library from the Resource folder to the Frameworks group.

The Project Hierarchy in the Xode Project Explorer
The Project Hierarchy in the Xode Project Explorer | Source

Develop BinaryDAO

The BinaryDAO custom is the model of this MVC design. This class will handle all the interaction with the SQLite database. This includes inserting the binary representation of the jpeg files, selecting the complete list of stored filenames and retrieving the binary data of a particular filename. Create new file as a subclass of the NSObject class in the Xcode templates. Naturally name the new subclass, BinaryDAO.

To interact with the SQLite database, I will need the SQLite library. Open the header file and add an import statement for the sqlite3.h library as shown in the BinaryDAO.h code listing below. Next I define four instance methods that I will implement in the implementation file:

  • -(void)insertBinaryData:(NSData*)binData:(NSString*)binName;
  • -(NSMutableArray*)selectBinaryStoredList;
  • -(NSData*)displaySelectedFile:(NSString*)selectedFile;
  • -(NSData*)getBinary:(NSString*)selectedFile;


insertBinaryData
The insertBinaryData, see code listing BinaryDAO.m below, will be called from klFileListViewController to insert the filename and the binary representation of the image file that is stored in the Resource folder of the project under the images group. The method has two arguments; one for the binary data and the other for the filename.

I first get an array of directories in the Documents using the NSSearchPathForDirectoriesInDomains method and passing the NSDocumentDirectory search property that represents the root Document directory in the project. Since I haven’t created any sub-directories, the array should only contain one item, the Documents directory itself.

I then use these value to get a handle on the BinaryDb.db file in the documents directory and open the database using the open command in SQLite. If the database is successfully opened I then proceed to define the insert query "Insert into binaryTbl(fileName, binaryData) VALUES(?,?);" that I will pass this to the sqlite3_prepare_v2 SQLite function along with the db object that I declared in the header file. On the same line I test the statement for any syntax errors. If the runtime finds any, the program will exit without inserting any data. At this point in the production app, you would need to add more logic to either advise the user of the problem or try figure if there is a problem with the database.

If no errors are found, I proceed to insert the filename as the first parameter using the sqlite3_bind_text SQLite function and I bind the binary data in the binData argument to the sqlite3_bind_blob SQLite function. The two import parameter of note are : [binData bytes], [binData length]. The first is the actual bytes in the binary data and the second parameter is the length of the binary data.

The remaining code cleans up the database operation and closes the database.

selectBinaryStoredList
This method, as the name suggest, fetches the list of stored filenames in the database and is the data source for the UIPickerView in the view controller. The first thing I do is create a new NSMutableArray instance variable, storedBinaryList. This array will hold the list of filenames from the database. Next I get a handle on the BinaryDb.db in the documents directory and attempt to open it. If there is an error, I exit gracefully as far as this sample is concerned.

If the database opens, I then define the SELECT statement to execute and I pass this query to the sqlite3_prepare_v2 SQLite function. If the query returns rows, I simple loop until there is no more rows, adding the returned values to the array. Once this process is complete, I clean up the database and exit, returning the list of filenames as a NSMutableArray.

displaySelectedFile
The displaySelectedFile follows the same pattern as the two previous methods. The method uses the selectedFile parameter to fetch the binary data from the database. The method opens the BinaryDb.db SQLite database and executes the query to fetch the data. If the query returns a result (row), the data is converted into a NSData and returns the corresponding UIImage. the process of displaying the UIIamge in the UIImageView is explained in the klFileViewerController implementation in that section below.

getBinary
This method is not a SQLite related method. It is a helper method to take an UIImage file and converted to a binary format using NSData. The method uses an UIImage parameter and fetches the corresponding file in the Resource folder in the app. Then it converts it to a binary representation of the jpeg and stores it as a NSData object which is returned to the calling method, (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath, in the klFileListViewController implementation file, see below.

The code for the BinaryDAO header and implementation is listing below. You can copy the code directly into your project if you are planning on reproducing this app or an app with a similar functionality.

BinaryDAO.h

//
//  BinaryDAO.h
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/20/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

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

@interface BinaryDAO : NSObject{
    sqlite3 *db;
}



-(void)insertBinaryData:(NSData*)binData:(NSString*)binName;

-(NSMutableArray*)selectBinaryStoredList;

-(NSData*)displaySelectedFile:(NSString*)selectedFile;

-(NSData*)getBinary:(NSString*)selectedFile;

@end

BinaryDAO.m

//
//  BinaryDAO.m
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/20/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

#import "BinaryDAO.h"

@implementation BinaryDAO


-(void)insertBinaryData:(NSData*)binData:(NSString*)binName{
    //Get list of directories in Document path
    NSArray * dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    
    //Define new path for database
    NSString * documentPath = [[dirPath objectAtIndex:0] stringByAppendingPathComponent:@"binaryDb.db"];
    
    
    if(!(sqlite3_open([documentPath UTF8String], &db) == SQLITE_OK))
    {
        NSLog(@"An error has occurred.");
        return;
    }else{
        const char *insertSQL = "Insert into binaryTbl(fileName, binaryData) VALUES(?,?);";

        sqlite3_stmt *sqlStatement;
        if(sqlite3_prepare_v2(db, insertSQL, -1, &sqlStatement, NULL) != SQLITE_OK)
        {
            NSLog(@"Problem with prepare statement");
            return;
        }else{
            sqlite3_bind_text(sqlStatement, 1, [binName UTF8String], -1, SQLITE_TRANSIENT);
            sqlite3_bind_blob(sqlStatement, 2, [binData bytes], [binData length], SQLITE_TRANSIENT);
            
            
            if(sqlite3_step(sqlStatement)==SQLITE_DONE){
                sqlite3_finalize(sqlStatement);
                sqlite3_close(db);
            }
            
        }
    }

    
}

-(NSMutableArray*)selectBinaryStoredList{
    NSMutableArray *storedBinaryList = [[NSMutableArray alloc]init];
    @try {
        NSFileManager *fileMgr = [NSFileManager defaultManager];
        //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 * dbPath = [[dirPath objectAtIndex:0] stringByAppendingPathComponent:@"binaryDb.db"];

        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.");
        }
                
        
        NSString * sqlQry = @"SELECT * FROM  binaryTbl";
        
        sqlite3_stmt *sqlStatement;
        if(sqlite3_prepare_v2(db, [sqlQry UTF8String], -1, &sqlStatement, NULL) != SQLITE_OK)
        {
            NSLog(@"Problem with prepare statement: %d", sqlite3_errcode(db));
        }
        
        
        
        while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
           
            NSString * viewFilename = [ NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,0)];
            NSLog(@"This is the filename %@",viewFilename);
            [storedBinaryList addObject:[NSString stringWithUTF8String:(char *) sqlite3_column_text(sqlStatement,0)]];
        }
    }
    @catch (NSException *exception) {
        NSLog(@"An exception occurred: %@", [exception reason]);
    }
    @finally {
        return storedBinaryList;
    }

}


-(NSData*)getBinary:(NSString*)filePath{
    NSData *bin=nil;
    NSString *root = [[NSBundle mainBundle] bundlePath];
    NSString *path = [[NSString alloc] initWithString:[root stringByAppendingString:[@"/"stringByAppendingString:filePath]]];
    
    NSLog(@"%@",path);
    
    bin = [[NSData alloc] initWithContentsOfFile:path];
    
    return bin;
}

-(NSData*)displaySelectedFile:(NSString*)selectedFile{
   
    NSData *image = [[NSData alloc]init];
    @try {
        NSFileManager *fileMgr = [NSFileManager defaultManager];
        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 * dbPath = [[dirPath objectAtIndex:0] stringByAppendingPathComponent:@"binaryDb.db"];
        

        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 occurred.");
        }
       
        NSString *sql=[NSString stringWithFormat: @"SELECT binaryData FROM binaryTbl where fileName= \"%@\"", selectedFile];
        
     
        sqlite3_stmt *sqlStatement;
        if(sqlite3_prepare_v2(db, [sql UTF8String], -1, &sqlStatement, NULL) != SQLITE_OK)
        {
            NSLog(@"Problem with prepare statement");
            
        }
        
        
        
        while (sqlite3_step(sqlStatement)==SQLITE_ROW) {
            
            const char *raw = sqlite3_column_blob(sqlStatement, 0);
            int rawLen = sqlite3_column_bytes(sqlStatement, 0);
            image = [NSData dataWithBytes:raw length:rawLen];
            
           
        }
    }
    @catch (NSException *exception) {
        NSLog(@"An exception occurred: %@", [exception reason]);
    }
    @finally {
        return image;
    }

}
@end

klAppDelegate

The AppDelegate is standard iOS construct. Actually it is necessary to have an AppDelegate in most iOS applications. The AppDelegate is like the “main” in other C based programs. iOS apps have a main as well but it is only used to call the AppDelegate. In this app, the AppDelegate will create a SQLite database and table dynamically if they don’t already exist.

In the header, the only changes I am making or need to make, it to import the sqlite3 library, see the klAppDelegate.h coding listing following this explanation and I create a SQLite instance called simply “db”. The actual database setup is done in the didFinishWithOptions method in the implementation file which we will look at next.

Locate the didFinishLaunchingWithOptions method is called when the app is loaded into memory. It is this instance method that I will create the binaryDb.db database and the table I will need to store the filename and corresponding binary.

First I define an NSError variable that will be used by the sqlite3_exec SQLite function. This function is quite handy since it encapsulates four important and related SQLite functions: sqlite3_prepare_v2, sqlite3_step and sqlite3_finalize(sqlStatement) and sqlite3_close(db).

I also define a Boolean variable FileExist which I will use to see if the database already exist, this exiting the method or to execute the query to create table. To create the database I get a handle on the documents directory, which is writable, and append the name of my database BinaryDb.db. I then pass this information to the sqlite3_open SQLite function. This function will not only open the database but will also automatically create it if it doesn’t exist. Once this is done, subsequent launching of the app will pass over the code since I use the FileExist boolean to check to see if the database already exist.

The sqlite3_exec as I mentioned before will execute the create table query: create table if not exists binaryTbl(fileName varchar, binaryData blob), using the “if not exists” statement which will check to see if the table already exists before creating it. This is handy to eliminate the risk of overwriting your table and store data. The complete code is the following code listing titled “klAppDelegate.h” and “klAppDelegate.m” respectfully. Now the database is setup and the model is completed, I will move to the Storyboard and associated view controllers.

klAppDelegate.h

//
//  klAppDelegate.h
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/3/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "sqlite3.h"


@interface klAppDelegate : UIResponder <UIApplicationDelegate>{
     sqlite3 * db;
   }

@property (strong, nonatomic) UIWindow *window;

@end

klAppDelegate.m

//
//  klAppDelegate.m
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/3/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

#import "klAppDelegate.h"

@implementation klAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    
    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");
                
            }
                    
        }
        
    }

    return YES;
}
							
- (void)applicationWillResignActive:(UIApplication *)application
{
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end

Develop ViewController (klFileViewerController - header)

The storyboard layout for this app will contain a UITableView and a UIViewController. So I will need to add a View Controller as a subclass of the UIViewController and another custom class as a subclass of the UITableViewController. I will cover the UIViewController in this section. The code for this custom class in provided below in the code listing titled klFileViewerController.h

Add a new file as a subclass of the UIViewController class from the templates in XCode (File - New File from the File menu in Xcode or command+N). Name it FileViewerController with or without the class prefix. In my example, the view controller is called klFileViewerController.

I will start by importing the BinaryDAO header file into my custom UIViewController class. I will then add the UIPickerViewDataSource and the UIPickerViewDelegate protocol statements. See the “klFileViewerController.h“ code listing below. Next four instance variables are added:

NSMutableArray *viewStoredFiles;
BinaryDAO *binOps;
@property (strong, nonatomic) IBOutlet UIPickerView *pickerList;
@property (strong, nonatomic) IBOutlet UIImageView *imgViewer;

The viewStoredFiles will provide the data for the UIPickerView and I will show how to populate it in the next section. The binOps BinaryDAO variable will be used to interface with the above mentioned methods to fetch the list of filenames for the UIPickerView data source and also to get the selected binary data to be converted into an UIImage for display in the UIImageViewer. The pickerList and imgViewer are IBOutlets that we will create later when I show you how to steup the Storyboard, so don’t add these two now.

I have also defined two instance methods: loadStoredFiles and displaySelectedJpg. The loadStoredFiles will be used to populate the UIPickerView using the viewStoredFiles and binOps. The displaySelectedJpg will be used to fetch the binary for the selected filename in the UIPickerView and converted it back to an UIImage for display in the UIImageViewer.

Once the header file is done and before getting to the implementation of the instance methods I am going to switch over to the Storyboard to setup the UIViewController and associated UIControls. i doing this because I am going to need to reference the two IBOutlets in the implementation file and also reference the UIViewController in the implementation file, so I need to set them up first.

klFileViewerController.h

//
//  klFileViewerController.h
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/22/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "BinaryDAO.h"


@interface klFileViewerController : UIViewController<UIPickerViewDataSource, UIPickerViewDelegate>

@property(nonatomic, strong) NSMutableArray *viewStoredFiles;
@property(nonatomic, strong) BinaryDAO *binOps;
@property (strong, nonatomic) IBOutlet UIPickerView *pickerList;
@property (strong, nonatomic) IBOutlet UIImageView *imgViewer;

-(void)loadStoredFiles;
-(UIImage*)displaySelectedJpg:(NSString*)selectedFilename;

@end

Develop Storyboard (UIViewController)

Since the Single View template came with an UIViewController, I will use that one in the storyboard for my needs. First I will select the ViewController custom class in the custom class field in the Identity inspector in Xcode. Take a look at the corresponding screenshot.

UIViewController in the Xcode IDE
UIViewController in the Xcode IDE | Source

With the custom class added to the UIViewController, I can then add the UIPickerview by dragging it from the Object Library in Xcode and likewise the UIImageView. The View Controller in the Storyboard should look mine in the following screenshot. Next I open the klFileViewerController header file using the Assistant editor, which should open alongside the storyboard. I then drag (ctrl+drag) a connection from the UIPickerView to the header file and name the IBOutlet “pickerList”. I repeat the process with the UIImageviewer and name this “imgViewer”.

I also drag and create two connections from the UIPickerView to the Proxy object at the bottom of the View Controller; one for the delegate and the other for the data source.

As far as the UIViewController, I am finished with the Storyboard. I will get back to it later when I work on the UITableViewController. To complete the UIViewController process, I will walk you through the changes to the klFileViewerController implementation file.

Develop ViewController (klFileViewerController - implementation)

The klFileViewerController implementation through the use of the UIPickerView protocols will display the list of stored jpeg files and and allow a user to select a file to display the corresponding image in the image viewer. You will find the code in the listing of the same name following this narrative.

First I start by synthesizing the variables I created in the header less the IBOutlets. These include the imgViewer, binOps, pickerlist and storedFileList. Since I am implementing the UIPickerView and its protocols, I need to implement the following UIPickerView instance methods.

  • (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
  • (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
  • (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row
  • forComponent:(NSInteger)component
  • (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component

numberOfRowsInComponent
This instance method tells the UIPickerView how many rows to display. It is usually the total number of elements in an array. I set this method to return the [storedFileList count].

numberOfComponentsInPickerView
The numberOfComponentsInPickerView method defines the number of columns the UIPickerView will have. A component is a column. I set this to 1.

titleForRow
The titleForRow tells the UIPickerView what value to display. This method will be called repeatedly for each element in the storedListfiles array and will display the element defined by the row argument as follows [viewStoredFiles objectAtIndex:row];

didSelectRow
Finally the didSelectRow method will capture the selected value from the user. I will use this value as the input for the displaySelectedJpg BinaryDAO instance method I spoke about earlier. The returned value is a re converted UIImage of the selected jpeg file.

In addition to these mandatory instance methods, I also implement the BinaryDAO following methods:

loadStoredFiles
The loadStoredFiles method uses the selectBinaryStoredList method from the BinaryDAO class to fetch the list of filenames that are stored in the database. These are assigned to an array which in turn is assigned to the storedFileList instance variable. Refer to the klFileViewerController.m code listing for the complete code.

displaySelectedJpg
This method is called by the didSelectRow above to get the selected binary from the database for the selected filename in the UIPickerView. The binary is converted to an UIImage and assigned to the UIImageView, imgViewer.

Finally I implement to the viewDidLoad and viewDidAppear methods of the standard View Controller. The viewDidLoad is called when the view controller is first called. Subsequent loads call the viewDidAppear method because the view controller is already in-memory so it just needs to placed on the top of the stack.

viewDidAppear
In this method I initialize the binOps object and call the loadStoredFiles method to get the filenames from the database and load them into the NSMutableArray viewStoredFiles.

viewDidAppear
This method is similar to the previous one, except I don’t initialize the BinaryDAO object. Instead the method loads the filename list as before into the viewStoredFiles NSMutableArray and calls the reloadAllComponents method of the UIPickerView to reload, or refresh the UIPickerView.

klFileViewerController.m

//
//  klFileViewerController.m
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/22/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

#import "klFileViewerController.h"


@interface klFileViewerController ()

@end

@implementation klFileViewerController
@synthesize pickerList;
@synthesize imgViewer;
@synthesize viewStoredFiles, binOps;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
	// Do any additional setup after loading the view.
    binOps = [[BinaryDAO alloc]init];
    [self loadStoredFiles];
 
    
}
-(void)viewDidAppear:(BOOL)animated
{
   // binOps = [[BinaryDAO alloc]init];
    [self loadStoredFiles];
    [pickerList reloadAllComponents];
}

- (void)viewDidUnload
{
    [self setPickerList:nil];
    [self setImgViewer:nil];
    [super viewDidUnload];
    // Release any retained subviews of the main view.
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
-(void)loadStoredFiles{
    viewStoredFiles = [[NSMutableArray alloc] initWithArray:(NSArray*)[binOps selectBinaryStoredList]];
    
    
       

    
}
-(UIImage*)displaySelectedJpg:(NSString*)selectedFilename{
   
    UIImage *storedImg=[[UIImage alloc]initWithData:[binOps displaySelectedFile:selectedFilename]];
    
    return storedImg;
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
       
    return [viewStoredFiles count];
}

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

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row
            forComponent:(NSInteger)component
{

    
    return [viewStoredFiles objectAtIndex:row];
    
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{

    

    self.imgViewer.image = [self displaySelectedJpg:[viewStoredFiles objectAtIndex:row]];
    
    
    
}



@end
The UITableViewController in the Xcode IDE
The UITableViewController in the Xcode IDE | Source
List of jpg files in Resource folder displayed in an UItableView
List of jpg files in Resource folder displayed in an UItableView | Source

Develop Storyboard (UITableView)

Next in the development process is to add the UITableViewController to the storyboard. I start by adding a UItableViewController to the storyboard. Then I select both view controllers and add a Tab Navigator (Menu - Editor - Embed In - Tab Navigator) to link both views together. For this I will simply change the labels of the tabs and not add any icons. To change the labels, select the each view controller in turn and select the tab item and in the Attributes inspector locate the Bar Item field and change the value.

Next I select the Cell Prototype and in the Attributes inspector, in the identifier field, I add the “fileCell” identifier. This will be used to populate the table. Before this UITableViewController is complete I need to create a custom UITableView class and add it as a custom class to the UITableViewController in the storyboard.

Develop TableViewController (header)

I add the custom UITableViewController class by selecting File - New File in Xcode. In template utilities, I select the Objective-C class. After turning the page, I enter the name for the class as FileListViewController. A prefix will added if you have opted to add one in your environment. I add one, so my custom class’ actual name is klFileListViewController.

I open the header and add import statement for the BinaryDAO class. I also add two instance variables:

  • fileList
  • binData

The fileList is a NSMutableArray and will be populated with the filenames of the jpeg files in the Resource folder of the app. I chose some image from Wiki Commons. The binData is a NSData instance variable and will be used to insert the binary data into the database.

With the UITableViewController created, I can complete the Storyboard implementation. So I which back over into the storyboard and select the UITableViewController and then open the Identity inspector and the select the klFileListViewController class from the list. Now I can complete the project by added the necessary code to the klFileListViewController implementation.

klFileListViewController.h

//
//  klFileListViewController.h
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/27/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "BinaryDAO.h"

@interface klFileListViewController : UITableViewController<UITableViewDelegate>


@property(nonatomic, strong) NSMutableArray *fileList;
@property(nonatomic, strong) BinaryDAO *binData;
@end

Develop TableViewController (implementation)

The UITableViewController template will have created all the required methods when I created the custom class. So all I really need to do is add the code to the right places and I’m finished. After synthesizing the two variables, I am going to focus my attention on the viewDidLoad method. In this method I will scan the Resource folder of the app and locate any and all the jpeg files that are there using a NSPredicate to filter on files that have a .jpg extension. Then the code adds these located files to the fileList array which will serve as the data source for the table.

numberOfSectionsInTableView
The other required method is the numberOfSectionsInTableView. This method defines the number of sections each row will have. Since this a simple list, I will set the return value to 1.

numberOfRowsInSection
This method tells the UITableViewController how many rows to display. The return value is usually the number of elements in the array. So here the return value is [fileList count].

cellForRowAtIndexPath
The cellForRowAtIndexPath method gets call repeatedly for each element in the data source or array. to make this work, change the cell identifier value to the value set on the cell prototype in the storyboard. In this app, I only display the filename, so I will set the cell textLabel value to the element in the fileList array.

didSelectRowAtIndexPath
Finally, the didSelectRowAtIndexPath method interacts with the insertBinaryData and method in the BinaryDAO class. Actually the method detects which row was selected and send the filename to the getBinary method which returns the binary representation of the jpeg.

That is it. Now you know how to store binary data in a SQLite database. You also know how to retrieve it and converted into a UIImage and display it an UIImageViewer.

klFileListViewController.m

//
//  klFileListViewController.m
//  StoreBinaryDatainSQLite
//
//  Created by Kevin Languedoc on 9/27/12.
//  Copyright (c) 2012 Kevin Languedoc. All rights reserved.
//

#import "klFileListViewController.h"

@interface klFileListViewController ()

@end

@implementation klFileListViewController
@synthesize fileList, binData;

- (id)initWithStyle:(UITableViewStyle)style
{
    self = [super initWithStyle:style];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (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 '.jpg'"];
    fileList = [[NSMutableArray alloc] initWithArray:[dirContents filteredArrayUsingPredicate:extFilter]];

    
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.fileList=nil;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark - Table view data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{

    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{

    return [fileList count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"fileCell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    
    cell.textLabel.text = [fileList objectAtIndex:indexPath.row];
    
    return cell;
}



#pragma mark - Table view delegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    binData = [[BinaryDAO alloc] init];
    NSString *fileName = [[NSString alloc] init];
    fileName=[fileList objectAtIndex:indexPath.row];
   
    [binData insertBinaryData: [binData getBinary:fileName]:fileName];
  
}

@end

More by this Author


Comments 5 comments

ambuj shukla 4 years ago

Sir Plz let me clear about BinaryDAO file...where it's coding is.


ambuj shukla 4 years ago

Oh. sorry sir I found it.


klanguedoc profile image

klanguedoc 4 years ago from Canada Author

ok great


chirupatel 3 years ago

could you please give me code about

Store Binary Data in an iPhone SQLite Database App.


klanguedoc profile image

klanguedoc 3 years ago from Canada Author

all code is downloaded from www.iosdev101.com

    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