iOS SQLite resets when Project is Re-ran in Simulator

mcnuggets

macrumors newbie
Original poster
Jan 2, 2009
18
0
I downloaded the source code located here on how to do a simple "To Do List":

iPhone Programming Tutorial ? Creating a ToDo List Using SQLite Part 4 | iPhone Programming Tutorials

What I notice is when I add anything to the list and then re-ran the simulator... whatever I added is not saved.

I installed the app on my phone and notice that the database is reseted when the Phone is turned off. The app works fine... but when the Phone is turned off (hold power button for 5 seconds) and when it turns back on... whatever I added to the To Do list is gone.

I spent several days on this and can't figure it out why it keeps getting deleted after phone is turned off. Source Code is here:
http://staging.icodeblog.com/wp-content/uploads/2008/09/todo-part-41.zip
 

ChristianVirtual

macrumors 601
May 10, 2010
4,096
266
* ** *
Didn't have the chance to check you source but my guess is you
a) try to write a DB in your bundle
b) recreate the DB when you restart your app

Make sure you create the DB only in your document folder or when using iCloud where the system tell you to do so. Check if the DB file is already there and just open it in that case. You can use the DB in your bundle as template but should create a working instance.

One more hint: sometimes the folder where the simulator place the binary is changing. Didn't myself yet fully understood under what conditions. But on the device that's not an issue.
 
Last edited:

mcnuggets

macrumors newbie
Original poster
Jan 2, 2009
18
0
Didn't have the chance to check you source but my guess is you
a) try to write a DB in your bundle
b) recreate the DB when you restart your app

Make sure you create the DB only in your document folder or when using iCloud where the system tell you to do so. Check if the DB file is already there and just open it in that case. You can use the DB in your bundle as template but should create a working instance.

One more hint: sometimes the folder where the simulator place the binary is changing. Didn't myself yet fully understood under what conditions. But on the device that's not an issue.
The database opens without a problem. And it writes to it without any issues. But when the phone is turned off... it wipes out whatever entry I wrote in there. It's as if I'm writing to the database temporarily. The database is stored locally and not in the cloud.
 

PhoneyDeveloper

macrumors 68040
Sep 2, 2008
3,114
93
Can you print out the path to your db file? Does the app come with a prebuilt db file or does it create a new one?
 

mcnuggets

macrumors newbie
Original poster
Jan 2, 2009
18
0
Can you print out the path to your db file? Does the app come with a prebuilt db file or does it create a new one?
The app comes with a prebuilt db that it edits. What I don't get is... it works... it's able to edit the database and add more info. It's just when the phone is turned off (loses power)... that's when it loses the data.

The source code comes with a todo.sqlite file. It's in the root directory where the project is located. On xcode I placed it under the "Resource" folder.

This is the code in the AppDelegate.m file:

- (void)createEditableCopyOfDatabaseIfNeeded {
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:mad:"todo.sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) return;
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:mad:"todo.sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
}
}


By the way thanks for the people helping me out on this. It's driving me nuts all week now.
 

admanimal

macrumors 68040
Apr 22, 2005
3,531
2
Are you absolutely sure that it only happens if the device is turned off? What if you kill the app from the task list and then re-run it?

Can you show us the code that calls createEditableCopyOfDatabaseIfNeeded (I'm guessing it's applicationDidFinishLaunching)?
 

mcnuggets

macrumors newbie
Original poster
Jan 2, 2009
18
0
Are you absolutely sure that it only happens if the device is turned off? What if you kill the app from the task list and then re-run it?

Can you show us the code that calls createEditableCopyOfDatabaseIfNeeded (I'm guessing it's applicationDidFinishLaunching)?
You're absolutely right. When you kill the app from the task list... all the data is gone. So basically it seem it's just temporarily writing to the database in memory.

I put the entire code of createEditableCopyofDabaseIFNeeded in my previous code. Please let me know if I'm missing anything.

Here's the code for applicationDidFinishLaunching:

- (void)applicationDidFinishLaunching:(UIApplication *)application {

[self createEditableCopyOfDatabaseIfNeeded];
[self initializeDatabase];

// Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
 

admanimal

macrumors 68040
Apr 22, 2005
3,531
2
It doesn't look like you're doing anything wrong in terms of creating the database if necessary. My guess is that you're not actually committing anything to the database, but rather just storing items in whatever data structures are in your program. Take a look at your SQL statements and make sure they are executing correctly.
 

RonC

macrumors regular
Oct 18, 2007
108
0
Chicago-area
It doesn't look like you're doing anything wrong in terms of creating the database if necessary. My guess is that you're not actually committing anything to the database, but rather just storing items in whatever data structures are in your program. Take a look at your SQL statements and make sure they are executing correctly.
You should have some code that looks roughly like this:
Code:
+(BOOL)commitChangesInContext:(NSManagedObjectContext *)context
{
    NSError *error = nil;
    
    if (![context save:&error]) {
        NSLog(@"Context save error: %@", error);
        abort();
    }
    
    return !error;
}
If you can't find save: run on a NSManagedObjectContext, then you ain't saving jack.
 

admanimal

macrumors 68040
Apr 22, 2005
3,531
2
You should have some code that looks roughly like this:
Code:
+(BOOL)commitChangesInContext:(NSManagedObjectContext *)context
{
    NSError *error = nil;
    
    if (![context save:&error]) {
        NSLog(@"Context save error: %@", error);
        abort();
    }
    
    return !error;
}
If you can't find save: run on a NSManagedObjectContext, then you ain't saving jack.
He's using plain SQLite, not Core Data, so there won't be any NSManagedObjectContext.
 

mcnuggets

macrumors newbie
Original poster
Jan 2, 2009
18
0
He's using plain SQLite, not Core Data, so there won't be any NSManagedObjectContext.
Someone suggested that I was calling initializeDatabase everytime the app loads but if I comment that out on applicationDidFinishLaunching... my app crashes.

- (void)initializeDatabase {
NSMutableArray *todoArray = [[NSMutableArray alloc] init];
self.todos = todoArray;
[todoArray release];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:mad:"todo.sqlite"];
// Open the database. The database was prepared outside the application.
if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {
// Get the primary key for all books.
const char *sql = "SELECT pk FROM todo";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
int primaryKey = sqlite3_column_int(statement, 0);
Todo *td = [[Todo alloc] initWithPrimaryKey:primaryKey database:database];

[todos addObject:td];
[td release];
}
}
sqlite3_finalize(statement);
} else {
sqlite3_close(database);
NSAssert1(0, @"Failed to open database with message '%s'.", sqlite3_errmsg(database));
// Additional error handling, as appropriate...
}

}


But here's something I found out. When re-running the simulator, ending the task, or turning off the phone... the entries I add or delete will update the database (or list). It's just the entries will have blank values. Maybe I am trying to reopen the original database?
 

phantax

macrumors member
Feb 2, 2009
72
0
Are you sure you are actually writing the data to the database? Have you tried actually reading it back out after a write and see if the values are not null.

My thought is that you are just updating your data source, whatever that may be, and not actually writing valid values to the database at the same time.
 

admanimal

macrumors 68040
Apr 22, 2005
3,531
2
Someone suggested that I was calling initializeDatabase everytime the app loads but if I comment that out on applicationDidFinishLaunching... my app crashes.
You need to call initializeDatabase because that is the code that actually opens the database file for use. Can you show us the code where you actually insert or update things in the database?