Wie Sie richtig nennen SQLite-Funktionen aus hintergrund-thread auf dem iPhone?

Verwende ich eine SQLite Datenbank in meinem iPhone app. Beim Start, es gibt einige Datenbank-Aktionen, die ich ausführen möchten, in einem separaten thread. (Ich mache dies vor allem auf Minimierung der startup-Zeit.)

Gelegentlich/zufällig, wenn diese Datenbank-Aufrufe aus dem hintergrund-thread, der die app zum Absturz, mit diesen Fehlern:

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'.'

Zwar kann ich nicht zuverlässig reproduzieren den Fehler, ich habe mich davon überzeugt, dass es aufgrund der Tatsache, dass SQLite-Funktionen sind dazu aufgerufen, in den beiden aktiven threads. Wie sollte ich rufe SQLite-Funktionen von einem separaten thread? Gibt es einen trick, ich bin fehlt? Ich bin ziemlich neu auf dem iPhone, SQLite, Objective-C, so dass es sein könnte etwas, das offensichtlich zu Ihnen, aber nicht so obviouse zu mir.

Hier sind einige code-Beispiele.

MainApplication.m:

- (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];
}

Aufgabe.m:

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 > ?) AND (status=0) AND (revert_status IS NOT NULL)";
        if (sqlite3_prepare_v2(db, sql, -1, &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);
}
Sie sollten sich wirklich überlegen, die Verwendung von Warteschlangen - entweder durch GCD-dispatch-Funktionen oder NSOperation. Erstellen einer Warteschlange erzeugt einfache Synchronisierung der Klasse der Arbeit.

InformationsquelleAutor ceperry | 2009-04-13

Schreibe einen Kommentar