What we will learn?
This tutorial will show you the basic of database programming on IPhone . We are going to use FMDatabase wrapper which simplifies the use of sqlite library. using FMDatabase we are going to create a program which populates a table with the database information and when a table cell is clicked the program will display additional information extracted from the database.
Things we will cover in this tutorial
We are going to learn the following thing:
-start a new project and add things we need to add database to our project
-learn a bit about FMDatabase and the functions available for us.
-extract information from the database
Source code for the project:
lets begin:
1. download the following files:
You downloaded here the wrapper functions for sqlite and the database we will use for the tutorial.
I'm not gonna show you in this tutorial how to create the database and if you want to create your own database u can find information on the subject in the following site:
Our database consists of 3 columns the first one is the primary key which is a unique index for every row in the database. the second one is a string of names of students, and the third ont is integer for the students id's.
the first column name is: 'pk', the second column name is: 'name' the third: 'id'
2. launch XCode
3. start a new project
4. choose navigation based application and name it:'database1'
5. right click classes in the groups and files and choose add -> new group
6. name the group database and copy the FMDatabase files to the new folder you just created
make sure you check the check box that says copy the files...(if needed)
7. copy students7.sqlite to the resource
make sure you check the check box that says copy the files...(if needed)
right click frameworks in the groups and files choose add->existing frameworks
choose libsqlite3.0.dylib from the list and press add. if you cant find it you need to manually find it so press add other goto developer/platforms/iphoneos.platform/developer/SDKs/iPhoneOS3.2sdk/usr/lib
and choose the file i mentioned earlier.
next we will create the openning window
8. right click classes choose add new files
9. choose UIViewController subclass and make sure only 'with xib...' check box is selected
10. name the class: OpenWinViewController
11. move the xib file that was created to the resources group
change the OpenWinViewController.h to look like this:
//
// OpenWinViewController.h
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import
@interface OpenWinViewController : UIViewController {
}
-(IBAction)btnNamesClick:(id)sender;
@end
// OpenWinViewController.h
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import
@interface OpenWinViewController : UIViewController {
}
-(IBAction)btnNamesClick:(id)sender;
@end
12. change the OpenWinViewController.m to look like this:
//
// OpenWinViewController.m
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import "OpenWinViewController.h"
#import "RootViewController.h"
@implementation OpenWinViewController
-(IBAction)btnNamesClick:(id)sender{
RootViewController* viewController = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
@end
// OpenWinViewController.m
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import "OpenWinViewController.h"
#import "RootViewController.h"
@implementation OpenWinViewController
-(IBAction)btnNamesClick:(id)sender{
RootViewController* viewController = [[RootViewController alloc] initWithNibName:@"RootViewController" bundle:nil];
[self.navigationController pushViewController:viewController animated:YES];
[viewController release];
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
@end
13. double click the OpenWinViewController.xib file that was created and drag a button
and connect the touch up inside event to btnNamesClick event
14. now double click MainWindow.xib and change the navigation controller child to be the new class we just created and the nib to be the nib we created.
we will now create the NSObject that will correspond to a row in the database
15. right click classes and choose add->new file
16. choose here objective c class and make sure u select subclass of nsobject.
17. name the classes: 'singleStudent'
18. change the singleStudent.h to look like this:
//
// singleStudent.h
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import
@interface singleStudent : NSObject {
int studentId;
int pk;
NSString* strName;
}
@property (nonatomic,assign)int studentId;
@property (nonatomic,assign)int pk;
@property (nonatomic,retain) NSString* strName;
-(id)initWithData:(int)intPk :(NSString *)name :(int)aId;
@end
// singleStudent.h
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import
@interface singleStudent : NSObject {
int studentId;
int pk;
NSString* strName;
}
@property (nonatomic,assign)int studentId;
@property (nonatomic,assign)int pk;
@property (nonatomic,retain) NSString* strName;
-(id)initWithData:(int)intPk :(NSString *)name :(int)aId;
@end
19. change the singleStudent.m to look like this:
//
// singleStudent.m
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import "singleStudent.h"
@implementation singleStudent
@synthesize studentId,pk,strName;
-(id)initWithData:(int)intPk :(NSString *)name :(int)aId{
self.studentId = aId;
self.strName = name;
self.pk = intPk;
return self;
}
@end
// singleStudent.m
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import "singleStudent.h"
@implementation singleStudent
@synthesize studentId,pk,strName;
-(id)initWithData:(int)intPk :(NSString *)name :(int)aId{
self.studentId = aId;
self.strName = name;
self.pk = intPk;
return self;
}
@end
20. change the database1appdelegate.h to look like this:
//
// database1AppDelegate.h
// database1
//
// Created by Yariv Katz on 10/25/10.
// Copyright YKSoftware 2010. All rights reserved.
//
#import
#import "FMDatabase.h"
@interface database1AppDelegate : NSObject{
UIWindow *window;
UINavigationController *navigationController;
NSMutableArray* aryDatabase;
NSString* databaseName;
NSString* databasePath;
FMDatabase* db;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic,retain) NSMutableArray* aryDatabase;
@end
// database1AppDelegate.h
// database1
//
// Created by Yariv Katz on 10/25/10.
// Copyright YKSoftware 2010. All rights reserved.
//
#import
#import "FMDatabase.h"
@interface database1AppDelegate : NSObject
UIWindow *window;
UINavigationController *navigationController;
NSMutableArray* aryDatabase;
NSString* databaseName;
NSString* databasePath;
FMDatabase* db;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic,retain) NSMutableArray* aryDatabase;
@end
21. change the database1appdelegate.m to look like this
change this function:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
[self updateNames];
[self checkAndCreateDatabase];
[self readWordsFromDatabase];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
// Override point for customization after application launch.
// Add the navigation controller's view to the window and display.
[self updateNames];
[self checkAndCreateDatabase];
[self readWordsFromDatabase];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
add these three new function to database1appdelegate.m:
-(void)updateNames{
databaseName = @"students7.sqlite";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
}
-(void) checkAndCreateDatabase{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:databasePath];
if(success) return;
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
[fileManager release];
}
-(void) readWordsFromDatabase {
[self updateNames];
db = [FMDatabase databaseWithPath:databasePath];
aryDatabase = [[NSMutableArray alloc] init];
[db setLogsErrors:TRUE];
[db setTraceExecution:TRUE];
if (![db open]) {
NSLog(@"Could not open db.");
return;
}else {
NSLog(@"oooooooohooo. DB Open....");
}
FMResultSet *rs = [db executeQuery:@"select * from student"];
while ([rs next]) {
int aID = [rs intForColumn:@"id"];
int intPk=[rs intForColumn:@"pk"];
NSString* aName = [rs stringForColumn:@"name"];
NSLog(@"%s",aName);
singleStudent* sStudent = [[singleStudent alloc] initWithData:intPk :aName :aID];
[aryDatabase addObject:sStudent];
[sStudent release];
}
[db close];
}
databaseName = @"students7.sqlite";
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:databaseName];
}
-(void) checkAndCreateDatabase{
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
success = [fileManager fileExistsAtPath:databasePath];
if(success) return;
NSString *databasePathFromApp = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:databaseName];
[fileManager copyItemAtPath:databasePathFromApp toPath:databasePath error:nil];
[fileManager release];
}
-(void) readWordsFromDatabase {
[self updateNames];
db = [FMDatabase databaseWithPath:databasePath];
aryDatabase = [[NSMutableArray alloc] init];
[db setLogsErrors:TRUE];
[db setTraceExecution:TRUE];
if (![db open]) {
NSLog(@"Could not open db.");
return;
}else {
NSLog(@"oooooooohooo. DB Open....");
}
FMResultSet *rs = [db executeQuery:@"select * from student"];
while ([rs next]) {
int aID = [rs intForColumn:@"id"];
int intPk=[rs intForColumn:@"pk"];
NSString* aName = [rs stringForColumn:@"name"];
NSLog(@"%s",aName);
singleStudent* sStudent = [[singleStudent alloc] initWithData:intPk :aName :aID];
[aryDatabase addObject:sStudent];
[sStudent release];
}
[db close];
}
add also the following imports:
#import "database1AppDelegate.h"
#import "RootViewController.h"
#import "singleStudent.h"
#import "RootViewController.h"
#import "singleStudent.h"
further explanation about the code we added you can find on the video
22. goto RootViewController.m and change the following function to look like this:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
database1AppDelegate *appDelegate = (database1AppDelegate *)[[UIApplication sharedApplication] delegate];
return [appDelegate.aryDatabase count];
}
database1AppDelegate *appDelegate = (database1AppDelegate *)[[UIApplication sharedApplication] delegate];
return [appDelegate.aryDatabase count];
}
23. change in the same file the following function:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
database1AppDelegate *appDelegate = (database1AppDelegate *)[[UIApplication sharedApplication] delegate];
singleStudent* sStudent =(singleStudent *) [appDelegate.aryDatabase objectAtIndex:indexPath.row];
cell.textLabel.text = [sStudent strName];
return cell;
}
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
database1AppDelegate *appDelegate = (database1AppDelegate *)[[UIApplication sharedApplication] delegate];
singleStudent* sStudent =(singleStudent *) [appDelegate.aryDatabase objectAtIndex:indexPath.row];
cell.textLabel.text = [sStudent strName];
return cell;
}
24. change the foolowing function in the same file to look like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
StudentViewController* viewController = [[StudentViewController alloc] initWithNibName:@"StudentViewController" bundle:nil];
self.title =@"Names";
database1AppDelegate *appDelegate = (database1AppDelegate *)[[UIApplication sharedApplication] delegate];
singleStudent* sStudent = [appDelegate.aryDatabase objectAtIndex:indexPath.row];
[self.navigationController pushViewController:viewController animated:YES];
[viewController.lblName setText:[sStudent strName]];
[viewController.lblID setText:[NSString stringWithFormat:@"%i",[sStudent studentId]]];
[viewController release];
}
StudentViewController* viewController = [[StudentViewController alloc] initWithNibName:@"StudentViewController" bundle:nil];
self.title =@"Names";
database1AppDelegate *appDelegate = (database1AppDelegate *)[[UIApplication sharedApplication] delegate];
singleStudent* sStudent = [appDelegate.aryDatabase objectAtIndex:indexPath.row];
[self.navigationController pushViewController:viewController animated:YES];
[viewController.lblName setText:[sStudent strName]];
[viewController.lblID setText:[NSString stringWithFormat:@"%i",[sStudent studentId]]];
[viewController release];
}
25. add the following imports to the same file above:
#import "RootViewController.h"
#import "database1AppDelegate.h"
#import "singleStudent.h"
#import "StudentViewController.h"
#import "database1AppDelegate.h"
#import "singleStudent.h"
#import "StudentViewController.h"
26. right click classes choose add new file and choose UIViewController subclass and make sure only the xib add xib check box is marked
27. name the new class: 'StudentViewController'
28 change the StudentViewController.h to look like this:
//
// StudentViewController.h
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import
@interface StudentViewController : UIViewController {
UILabel* lblName;
UILabel* lblID;
}
@property(nonatomic,retain)IBOutlet UILabel* lblName;
@property(nonatomic,retain)IBOutlet UILabel* lblID;
@end
// StudentViewController.h
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import
@interface StudentViewController : UIViewController {
UILabel* lblName;
UILabel* lblID;
}
@property(nonatomic,retain)IBOutlet UILabel* lblName;
@property(nonatomic,retain)IBOutlet UILabel* lblID;
@end
29. change the StudentViewController.m to look like this:
//
// StudentViewController.m
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import "StudentViewController.h"
@implementation StudentViewController
@synthesize lblName,lblID;
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
@end
// StudentViewController.m
// database1
//
// Created by Yariv Katz on 10/26/10.
// Copyright 2010 YKSoftware. All rights reserved.
//
#import "StudentViewController.h"
@implementation StudentViewController
@synthesize lblName,lblID;
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
}
@end
30. double click the StudentViewController.xib and add two labels connect the upper one to lblname and the lower one to lblID.
all done you can launch and play with your new program.
for full source code: