iOS: Multiple queries crashing app
I have an application where I access an SQLite database several times.. But, once I've accessed the database one time, all following attem开发者_如何学Gopts cause the app to crash... I'm not sure if it's because the database has not been properly released...
An example, I run a search to populate a tableview with names of artists. Once I select an artist, I'm navigated to a new tableview, where I want to populate it with the artist's works.
But here's the problem. I access the database to populate the first view, but when I want to populate the second view, it doesn't enter sqlite3_prepare_v2 of the query... so this must mean the database is still in use by the old query..
So what is the proper way of handling closing a database after use?
Currently I do a query like this:
-(NSArray *)findAllArtists
{
NSMutableArray *returnArray = [[[NSMutableArray alloc] init] autorelease];
NSString *query = @"SELECT * FROM Painting GROUP BY Artist";
sqlite3_stmt *statement;
if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil)
== SQLITE_OK)
{
while (sqlite3_step(statement) == SQLITE_ROW)
{
char *uniqueIdChars = (char *) sqlite3_column_text(statement, 0);
char *artistChars = (char *) sqlite3_column_text(statement, 1);
NSString *uniqueId = [[NSString alloc] initWithUTF8String:uniqueIdChars];
NSString *artist = [[NSString alloc] initWithUTF8String:artistChars];
PaintingInfo *info = [[PaintingInfo alloc] initWithUniqueId:uniqueId artist:artist];
[returnArray addObject:info];
[uniqueId release];
[artist release];
}
sqlite3_finalize(statement);
}
sqlite3_close(database);
return returnArray;
}
You should look at fmdb wrapper at github. Even if you don't use it, look at the code.
Where are you opening the database? You're closing it in this code. Before you call it again, it needs to be open. You should consider just keeping it open for the duration of the single user iOS app and closing when you're done. What happens if you simply remove the close call?
The first thing you should do is check all your return codes for sqlite calls. for example, with step you're not handling anything other than SQLITE_ROW. At least log others. Also for finalize and close you're not handling or logging others.
Also, you're preparing (compiling) the sql statement but your not saving it off. prepare_v2 gives you back a compiled statement. Save it off as a member variable and call reset against it before using it again.
To answer your specific question of how to close - you need to consider that some statements may not have been finalized. Here's my close method: (BTW, ENDebug is my wrapper over NSLog)
- (void)close
{
if (_sqlite3)
{
ENInfo(@"closing");
[self clearStatementCache];
int rc = sqlite3_close(_sqlite3);
ENDebug(@"close rc=%d", rc);
if (rc == SQLITE_BUSY)
{
ENError(@"SQLITE_BUSY: not all statements cleanly finalized");
sqlite3_stmt *stmt;
while ((stmt = sqlite3_next_stmt(_sqlite3, 0x00)) != 0)
{
ENDebug(@"finalizing stmt");
sqlite3_finalize(stmt);
}
rc = sqlite3_close(_sqlite3);
}
if (rc != SQLITE_OK)
{
ENError(@"close not OK. rc=%d", rc);
}
_sqlite3 = NULL;
}
}
finally, consider adding much more logging along with the return codes so you can get more insight.
Hope that helps.
精彩评论