Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to properly call SQLite functions from background thread on iPhone?
    primarykey
    data
    text
    <p>I'm using an SQLite database in my iPhone app. At startup, there are some database actions that I want to perform in a separate thread. (I'm doing this mainly to minimize startup time.)</p> <p>Occasionally/randomly, when these database calls are made from the background thread, the app will crash with these errors:</p> <pre><code>2009-04-13 17:36:09.932 Action Lists[1537:20b] *** Assertion failure in -[InboxRootViewController getInboxTasks], /Users/cperry/Dropbox/Projects/iPhone GTD/GTD/Classes/InboxRootViewController.m:74 2009-04-13 17:36:09.932 Action Lists[1537:3d0b] *** Assertion failure in +[Task deleteCompletedTasksInDatabase:completedMonthsAgo:], /Users/cperry/Dropbox/Projects/iPhone GTD/GTD/Classes/Data Classes/Task.m:957 2009-04-13 17:36:09.933 Action Lists[1537:20b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error: failed to prepare statement with message 'library routine called out of sequence'.' 2009-04-13 17:36:09.933 Action Lists[1537:3d0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error: failed to prepare statement with message 'library routine called out of sequence'.' </code></pre> <p>Although I can't reliably reproduce the error, I've convinced myself that it is due to the fact that SQLite functions are being called in both active threads. How <em>should</em> I be calling SQLite functions from a separate thread? Is there a trick I'm missing? I'm pretty new to the iPhone, SQLite, and Objective-C, so it might be something that's obvious to you, but not so obviouse to me.</p> <p>Here are some code samples.</p> <p>MainApplication.m:</p> <pre><code>- (void)applicationDidFinishLaunching:(UIApplication *)application { // Take care of jobs that have to run at startup [NSThread detachNewThreadSelector:@selector(startUpJobs) toTarget:self withObject:nil]; } // Jobs that run in the background at startup - (void)startUpJobs { // Anticipating that this method will be called in its own NSThread, set up an autorelease pool. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; // Get user preferences NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; // This Class Method calls SQLite functions and sometimes causes errors. [Task revertFutureTasksStatus:database]; [pool release]; } </code></pre> <p>Task.m:</p> <pre><code>static sqlite3_stmt *revert_future_statement = nil; + (void) revertFutureTasksStatus:(sqlite3 *)db { if (revert_future_statement == nil) { // Find all tasks that meet criteria static char *sql = "SELECT task_id FROM tasks where ((deleted IS NULL) OR (deleted=0)) AND (start_date &gt; ?) AND (status=0) AND (revert_status IS NOT NULL)"; if (sqlite3_prepare_v2(db, sql, -1, &amp;revert_future_statement, NULL) != SQLITE_OK) { NSAssert1(0, @"Error: failed to prepare update statement with message '%s'.", sqlite3_errmsg(db)); } } // Bind NOW to sql statement NSDate *now = [[NSDate alloc] init]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd"]; NSString *nowString = [formatter stringFromDate:now]; sqlite3_bind_text(revert_future_statement, 1, [nowString UTF8String], -1, SQLITE_TRANSIENT); [now release]; [formatter release]; // We "step" through the results - once for each row. while (sqlite3_step(revert_future_statement) == SQLITE_ROW) { // Do things to each returned row } // Reset the statement for future reuse. sqlite3_reset(revert_future_statement); } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload