Ich habe ein Problem mit einer neuen Anwendung im iPhone SDK, die SQLite als DB-Backend verwendet.
Gelegentlich beendet meine App das Laden von Daten in meine UITableViews und nach dem Herunterladen der Gerätedatenbank über den Organizer kann ich über die Befehlszeile auf die SQLite DB zugreifen. Ich kann bestimmte Tabellen in Ordnung aber nicht andere abfragen, ohne einen "SQL-Fehler: Datenbank-Disk-Image ist fehlerhaft" -Fehler. Sehen Sie sich eine SQLite-Sitzung an:
%Vor%In diesem Beispiel funktioniert meine Benutzertabelle einwandfrei, aber meine Elementtabelle ist fehlerhaft, was mit dem übereinstimmt, was ich in meiner App sehe, wo die Elemente nicht geladen werden. Die App stürzt nicht ab, die Daten werden aufgrund dieses fehlerhaften Fehlers nicht geladen.
Irgendwelche Ideen, warum das passiert? Mein einziger Gedanke ist, dass die DB möglicherweise beschädigt wird, weil ich über einen Hintergrund-Thread innerhalb der App in die SQLite-DB schreibe. Ich lade Daten von einem Webserver über eine NSOperationQueue in einem Hintergrundthread herunter und aktualisiere die SQLite DB mit den heruntergeladenen Daten. Würde das Schreiben in die DB in einem Hintergrund-Thread (während es möglicherweise vom Haupt-Thread liest) die DB beschädigen, oder ist es etwas anderes?
Sie müssen beim Debugging auf Hintergrund-Threads, die auf die Datenbank zugreifen, sehr vorsichtig sein! Wenn der Debugger die Verarbeitung anhält (z. B. an einem Haltepunkt), werden alle Threads pausiert, einschließlich Threads, die sich möglicherweise mitten in einem Datenbankaufruf befinden, irgendwo zwischen einer Datenbank "Öffnen" und einer Datenbank "Schließen" / p>
Wenn Sie an einem Haltepunkt angehalten werden und auf das Stopp-Zeichen in Xcode klicken, wird Ihre App sofort beendet. Dies führt sehr oft zu Fehlern wie dem, den Sie gesehen haben, oder dem Fehler "beschädigte Datenbank".
Es gibt wirklich keine Lösung (weil es keine Möglichkeit gibt, das Verhalten von "stop tasks" zu ändern, aber ich habe einige Techniken entwickelt, um es zu mildern: 1. Fügen Sie Code hinzu, um zu erkennen, dass die App den Hintergrund aufruft und die db-Vorgänge ordnungsgemäß beendet werden. 2. Verwenden Sie niemals das Stoppzeichen, um die Verarbeitung während des Debuggens anzuhalten. Wenn Sie mit einem Haltepunkt fertig sind, dann "Weiter", drücken Sie die Home-Taste am Simulator oder Gerät (was den in Schritt 1 hinzugefügten Code auslösen sollte), warten Sie auf die App im Hintergrund, DANN können Sie den Lauf stoppen.
In meinem Fall hatte das mit iOS 7 zu tun: Auf iOS 7 Core Data verwendet jetzt den SQLite WAL Journaling-Modus, der Daten in eine .db-wal
-Datei anstatt direkt in die .db
-Datei schreibt. In meiner App würde ich eine vorbereitete .db
-Datei während eines App-Updates in Library/Application Support
kopieren. Das Problem war, dass eine alte .db-wal
-Datei immer noch in diesem Verzeichnis war und ich nur die .db
-Datei ersetzte. Auf diese Weise endete ich mit einer .db
-Datei, die nicht mit der alten .db-wal
-Datei synchronisiert war.
Es gibt zwei Lösungen für dieses Problem:
.db
, .db-wal
und .db-shm
gelöscht werden, bevor Sie Ihre neue .db
-Datei an ihren Platz kopieren. Abhängig davon, wie SQLite kompiliert wird, ist es möglicherweise threadsicher. Wenn Sie die integrierte Version verwenden, verfügt sie möglicherweise nicht über die gewünschten Kompilierzeitoptionen.
Für unsere App mussten wir unsere eigene SQLite rollen, um eine Volltextsuche hinzuzufügen. Werfen Sie einen Blick auf diese Seite .