Adding 2 or 3 rows at a time in the database fails to add the record in iPhone
I have an application which have a system add button the navigation bar .on clicking the add button a new page opens which consists of 3 textfields named txtJourneyname, txtlocationName, txtdescription.
On this page there is a save button on the navigation so when the user enters the value in the textfields and click the save button the values are saved in the database. But I am having a problem that when I add 2 or 3 values at a time only the first value is entered in the database. I want all the values that I enter must be saved in the database.
This is my appdelegate code:
#import <UIKit/UIKit.h>
@class NewJourney;
@class JourneyController;
@interface SqltestAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
UINavigationController *navigationController;
JourneyController *jList;
//this is to hold the list of journey
NSMutableArray *journeyList;
}
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;
@property (nonatomic, retain) NSMutableArray *journeyList;
-(void) copyDatabaseIfNeeded;
-(NSString *)getDBPath;
-(void)removeJourney:(NewJourney *)journeyobj;
-(void)addJourney:(NewJourney *)journeyobj;
@end
.m file
#import "SqltestAppDelegate.h"
#import "JourneyController.h"
#import "NewJourney.h"
@implementation SqltestAppDelegate
@synthesize window;
@synthesize navigationController;
@synthesize journeyList;
#pragma mark -
#pragma mark Application lifecycle
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after application launch.
//this function is used to copy database to user's phone if needed.
[self copyDatabaseIfNeeded];
//Initializing the journeylist array.
NSMutableArray *tempArray = [[NSMutableArray alloc]init];
self.journeyList = tempArray;
[tempArray release];
//this is function is used when once the db is copied, get the initial data to display on screen.
[NewJourney getInitialDataToDisplay:[self getDBPath]];
//configuring and displaying the window
jList = [[JourneyController alloc]initWithNibName:@"JourneyController" bundle:nil];
self.navigationController = [[[UINavigationController alloc]initWithRootViewController:jList]autorelease];
[window addSubview:self.navigationController.view];
[window makeKeyAndVisible];
}
- (void)applicationWillTerminate:(UIApplication *)application {
[self.journeyList makeObjectsPerformSelector:@selector(saveAllData)];
[NewJourney finalizeStatements];
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
[self.journeyList makeObjectsPerformSelector:@selector(saveAllData)];
}
- (void)dealloc {
[journeyList release];
[navigationController release];
[window release];
[super dealloc];
}
- (void) copyDatabaseIfNeeded {
//Using NSFileManager we can perform many file system operations.
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSStr开发者_运维知识库ing *dbPath = [self getDBPath];
NSLog(@"%@",dbPath);
BOOL success = [fileManager fileExistsAtPath:dbPath];
if(!success) {
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"journey.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:dbPath error:&error];
if (!success)
NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
}
}
- (NSString *) getDBPath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory , NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
return [documentsDir stringByAppendingPathComponent:@"journey.sqlite"];
}
- (void)removeJourney:(NewJourney *)journeyobj {
[journeyobj deleteCoffee];
[journeyList removeObject:journeyobj];
}
- (void)addJourney:(NewJourney *)journeyobj {
[journeyobj addCoffee];
[journeyList addObject:journeyobj];
}
@end
This is my newjourney class
#import <UIKit/UIKit.h>
#import <sqlite3.h>
@interface NewJourney : NSObject
{
NSInteger journeyID;
NSString *journeyName;
NSString *locationName;
NSString *description;
BOOL isDirty;
BOOL isDetailViewHydrated;
}
@property(nonatomic, readonly)NSInteger journeyID;
@property(nonatomic, copy) NSString *journeyName;
@property(nonatomic,copy) NSString *locationName;
@property(nonatomic,copy) NSString *description;
@property(nonatomic,readwrite) BOOL isDirty;
@property(nonatomic,readwrite) BOOL isDetailViewHydrated;
+(void) getInitialDataToDisplay:(NSString*)dbPath;
+(void) finalizeStatements;
-(id) initWithPrimaryKey:(NSInteger)pk;
-(void)deleteCoffee;
-(void)addCoffee;
//-(void)hydrateDetailViewData;
-(void)saveAllData;
@end
.m
#import "NewJourney.h"
#import "SqltestAppDelegate.h"
static sqlite3 *database = nil;
static sqlite3_stmt *deleteStmt = nil;
static sqlite3_stmt *addStmt = nil;
static sqlite3_stmt *detailSmt = nil;
static sqlite3_stmt *updateStmt = nil;
@implementation NewJourney
@synthesize journeyID,journeyName,locationName,description,isDirty,isDetailViewHydrated;
+(void) getInitialDataToDisplay:(NSString *)dbPath
{
SqltestAppDelegate *appDelegate =(SqltestAppDelegate *)[[UIApplication sharedApplication]delegate];
if (sqlite3_open([dbPath UTF8String], &database) == SQLITE_OK)
{
const char *sql = "select JourneyID,JourneyName,LocationName,Description from UserJourney";
sqlite3_stmt *selectstmt;
if (sqlite3_prepare_v2(database, sql, -1, &selectstmt, NULL) == SQLITE_OK)
{
while (sqlite3_step(selectstmt) == SQLITE_ROW)
{
NSInteger primaryKey = sqlite3_column_int(selectstmt, 0);
NewJourney *newobj = [[NewJourney alloc]initWithPrimaryKey:primaryKey];
newobj.journeyName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(selectstmt, 1)];
newobj.isDirty = NO;
[appDelegate.journeyList addObject:newobj];
//[appDelegate.journeyList release];
[newobj release];
}
}
}
else {
sqlite3_close(database);
}
}
+(void) finalizeStatements
{
if (database) sqlite3_close(database);
if (database) sqlite3_finalize(deleteStmt);
if (database) sqlite3_finalize(addStmt);
if (database) sqlite3_finalize(detailSmt);
if (database) sqlite3_finalize(updateStmt);
}
-(id) initWithPrimaryKey:(NSInteger)pk
{
[super init];
journeyID = pk;
isDetailViewHydrated = NO;
return self;
}
-(void) deleteCoffee
{
if (deleteStmt == nil)
{
const char *sql = "delete from UserJourney where JourneyID = ?";
if (sqlite3_prepare_v2(database, sql, -1, &deleteStmt,NULL) != SQLITE_OK)
{
NSAssert1(0,@"Error while creating delete statemnet.'%s'",sqlite3_errmsg(database));
}
//when binding parameters, index starts from 1 and not zero.
sqlite3_bind_int(deleteStmt, 1, journeyID);
if (SQLITE_DONE != sqlite3_step(deleteStmt))
{
NSAssert1(0,@"Error while deleting. '%s'",sqlite3_errmsg(database));
}
sqlite3_reset(deleteStmt);
}
}
-(void) addCoffee
{
if (addStmt == nil)
{
const char *sql = "insert into UserJourney(JourneyName,LocationName,Description) Values(?,?,?)";
if (sqlite3_prepare_v2(database, sql, -1,&addStmt , NULL) != SQLITE_OK)
{
NSAssert1(0,@"Error while creating add statement.'%s'",sqlite3_errmsg(database));
}
sqlite3_bind_text(addStmt, 1 , [journeyName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStmt, 2 , [locationName UTF8String],-1, SQLITE_TRANSIENT);
sqlite3_bind_text(addStmt, 3, [description UTF8String],-1, SQLITE_TRANSIENT);
if (SQLITE_DONE != sqlite3_step(addStmt))
{
NSAssert1(0,@"Error while inserting data. '%s'",sqlite3_errmsg(database));
}else
{
journeyID = sqlite3_last_insert_rowid(database);
}
sqlite3_reset(addStmt);
}
}
-(void)saveAllData
{
if (isDirty) {
if (updateStmt == nil) {
const char *sql = "update UserJourney Set JourneyName = ?,LocationName = ?,Description = ? Where JourneyID =?";
if (sqlite3_prepare_v2(database, sql, -1, &updateStmt, NULL) != SQLITE_OK)
NSAssert1(0,@"Error while creating update statement. '%s'",sqlite3_errmsg(database));
}
sqlite3_bind_text(updateStmt, 1, [journeyName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(updateStmt, 2, [locationName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(updateStmt, 3, [description UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(updateStmt,4, journeyID);
if(SQLITE_DONE != sqlite3_step(updateStmt))
NSAssert1(0, @"Error while updating. '%s'", sqlite3_errmsg(database));
sqlite3_reset(updateStmt);
isDirty = NO;
}
[journeyName release];
//this is to test whether it will work or not.
[locationName release];
[description release];
journeyName = nil;
//this is to test .
locationName = nil;
description = nil;
isDetailViewHydrated = NO;
}
- (void)setJourneyName:(NSString *)newName {
self.isDirty = YES;
[journeyName release];
journeyName= [newName copy];
}
- (void)setLocationName:(NSString *)newLocation {
self.isDirty = YES;
[locationName release];
locationName = [newLocation copy];
}
- (void)setDescription:(NSString *)newDescription {
self.isDirty = YES;
[description release];
description = [newDescription copy];
}
- (void) dealloc {
[journeyName release];
[locationName release];
[description release];
[super dealloc];
}
@end
This is my JourneyController class
#import <UIKit/UIKit.h>
@class NewJourney,AddController;
@class SqltestAppDelegate;
@interface JourneyController : UITableViewController
{
SqltestAppDelegate *appDelegate;
AddController *addController;
UINavigationController *addNavigationController;
}
@end
.m
#import "JourneyController.h"
#import "NewJourney.h"
#import "AddController.h"
#import "SqltestAppDelegate.h"
@implementation JourneyController
#pragma mark -
#pragma mark View lifecycle
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(add_Clicked:)];
appDelegate = (SqltestAppDelegate *)[[UIApplication sharedApplication] delegate];
self.title = @"Journey List";
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
#pragma mark -
#pragma mark Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
// Return the number of rows in the section.
return [appDelegate.journeyList count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier]autorelease];
}
//Get the object from the array.
NewJourney *newobj = [appDelegate.journeyList objectAtIndex:indexPath.row];
//Set the journeyname.
cell.textLabel.text = newobj.journeyName;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
// Configure the cell...
return cell;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tv commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source.
///this is the code to get the object to delete from array.
NewJourney *newobj = [appDelegate.journeyList objectAtIndex:indexPath.row];
[appDelegate removeJourney:newobj];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
[self.tableView setEditing:editing animated:YES];
//Do not let the user add if the app is in edit mode.
if(editing)
self.navigationItem.leftBarButtonItem.enabled = NO;
else
self.navigationItem.leftBarButtonItem.enabled = YES;
}
- (void) add_Clicked:(id)sender {
if(addController == nil)
addController = [[AddController alloc] initWithNibName:@"AddNew" bundle:nil];
if(addNavigationController == nil)
addNavigationController = [[UINavigationController alloc] initWithRootViewController:addController];
[self.navigationController presentModalViewController:addNavigationController animated:YES];
}
#pragma mark -
#pragma mark Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:@"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
#pragma mark -
#pragma mark Memory management
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Relinquish ownership any cached data, images, etc. that aren't in use.
}
- (void)viewDidUnload {
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
// For example: self.myOutlet = nil;
}
- (void)dealloc {
[addController release];
[addNavigationController release];
[super dealloc];
}
@end
This is my addcontroller class
#import <UIKit/UIKit.h>
@class NewJourney;
@interface AddController : UIViewController {
IBOutlet UITextField *txtJourneyName;
IBOutlet UITextField *txtLocationName;
IBOutlet UITextField *txtDescription;
}
@end
.m
#import "AddController.h"
#import "NewJourney.h"
#import "SqltestAppDelegate.h"
@implementation AddController
// Implement viewDidLoad to do additional setup after loading the view.
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Add Coffee";
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
target:self action:@selector(cancel_Clicked:)] autorelease];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemSave
target:self action:@selector(save_Clicked:)] autorelease];
self.view.backgroundColor = [UIColor groupTableViewBackgroundColor];
}
- (void) viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//Set the textboxes to empty string.
txtJourneyName.text = @"";
txtLocationName.text = @"";
txtDescription.text = @"";
//Make the coffe name textfield to be the first responder.
[txtJourneyName becomeFirstResponder];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void) save_Clicked:(id)sender {
SqltestAppDelegate *appDelegate = (SqltestAppDelegate *)[[UIApplication sharedApplication] delegate];
//Create a Coffee Object.
NewJourney *coffeeObj = [[NewJourney alloc] initWithPrimaryKey:0];
coffeeObj.journeyName = txtJourneyName.text;
//NSDecimalNumber *temp = [[NSDecimalNumber alloc] initWithString:txtPrice.text];
//coffeeObj.price = temp;
//[temp release];
coffeeObj.isDirty = NO;
coffeeObj.isDetailViewHydrated = YES;
//Add the object
[appDelegate addJourney:coffeeObj];
//Dismiss the controller.
[self.navigationController dismissModalViewControllerAnimated:YES];
}
- (void) cancel_Clicked:(id)sender {
//Dismiss the controller.
[self.navigationController dismissModalViewControllerAnimated:YES];
}
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[theTextField resignFirstResponder];
return YES;
}
- (void)dealloc {
[txtJourneyName release];
[txtLocationName release];
[txtDescription release];
[super dealloc];
}
@end
The code in addCoffee
will only ever run once because once you have created addStmt
, the next time you execute that method, the if
statement causes the entire code to be omitted including the actual insert.
On a separate note, you must finalize your sqlite3 statements before closing the database.
精彩评论