开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜