Swift4からSQLite3のデータベースでWALモードのものに実はアクセスは普通にできますが、サンドボックスの時に問題が起きます。
サンドボックス時に一般的なフォルダにsqliteのファイルがあるとWALモードの場合は一度目のアクセスでデータベースは開けるのですが、SQL文のチェックの為に二度目のアクセスをするとエラーになります。
これを回避する為に私が取ったのはsqliteファイルをキャッシュフォルダにコピーをして、そのキャッシュフォルダにコピーしたsqliteに対してSQL文を実行し、アプリを終了する時にもともとあったsqliteファイルを削除して、先ほどのコピーしたsqliteファイルを元々の場所にコピーをして戻して、キャッシュフォルダのsqliteファイルを削除します。
データベースを読み込む時の処理例
let op = NSOpenPanel() op.canChooseFiles = true op.canChooseDirectories = false op.allowsMultipleSelection = false op.allowedFileTypes = ["sqlite"] op.directoryURL = myURL if op.runModal() != NSApplication.ModalResponse.OK { return } //ファイルのコピーの処理 let manager = FileManager.default //キャッシュフォルダのパスの取得 let localPath = manager.urls(for: .cachesDirectory, in: .userDomainMask).first! //キャッシュにコピーする時のファイル名は固定にしています。 let cacheFolder = "sample.sqlite" let localBackupDirectory = localPath.appendingPathComponent(cacheFolder) do { //コピー処理 try manager.copyItem(at: op.url!, to: localBackupDirectory) } catch { print("Copy files Error: \(error)") return } //以下はSQL文の実行例ですが、sqlite3のAPIで直に操作しています。 var db: OpaquePointer? = nil let sqlRet0 = sqlite3_open_v2(localBackupDirectory.absoluteString, &db, SQLITE_OPEN_URI | SQLITE_OPEN_SHAREDCACHE | SQLITE_OPEN_NOMUTEX | SQLITE_OPEN_READWRITE, nil) if sqlRet0 == SQLITE_OK { print("Database is opened.") } else { print("Database couldn't be opened.") return } let queryStatementString = "SELECT id, name FROM groups" var queryStatement: OpaquePointer? = nil let sqlRet1 = sqlite3_prepare_v2(db, queryStatementString, -1, &queryStatement, nil) print(sqlRet1) if sqlRet1 == SQLITE_OK { print("SQL statement is OK.") while (sqlite3_step(queryStatement) == SQLITE_ROW) { let id = sqlite3_column_int(queryStatement, 0) let titleCol1 = sqlite3_column_text(queryStatement, 1) var title: String? = nil if titleCol1 == nil { title = "" } else { title = String(cString: titleCol1!) } print("id: \(id), name: \(title!)") } } //sqlite3の後処理 sqlite3_finalize(queryStatement) sqlite3_close(db) //元の位置に戻すための処理 do { //元々のファイルを削除。上書きコピーができないからです。 try manager.removeItem(at: op.url!) //キャッシュフォルダのファイルを元々の場所にコピー try manager.copyItem(at: localBackupDirectory!, to: op.url!) //キャッシュフォルダのファイルを削除。これが残っていると次にコピーできない。 try manager.removeItem(at: localBackupDirectory!) } catch { print("\(error)") let panel = NSAlert() panel.messageText = "ファイルのコピーに失敗しました。" panel.runModal() return }