title: How to properly call SQLite functions from background thread on iPhone?
body: <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 obvious to you, but not so obvious 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 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>