2017-12-09 50 views
1

作成した引用符のデータベースに書き込もうとしています。ユーザーが「お気に入り」ボタンを選択すると、SQLiteデータベースのお気に入りの列に1(または真)の値が追加されます。私は、データベースとするとき、私はこのコードを実行するに書き込むことはできませんいくつかの理由について:Swift GRDBデータベースへの書き込みエラー "読み取り専用データベースの書き込みを試みよう"

@IBAction func addFavorite(_ sender: Any) { 
     var configuration = Configuration() 
     configuration.readonly = false 
     let dbPath = Bundle.main.path(forResource: "data", ofType: "db")! 
     let dbQueue = try! DatabaseQueue(path: dbPath, configuration: configuration) 

     try! dbQueue.inDatabase { db in 
      try db.execute(""" 
UPDATE quotes SET favorite = 1 WHERE quote = ?; 
""", 
              arguments: [quoteLabel.text]) 
    } 

私は結果はデー​​タベースへの書き込みやお気に入りの欄に1を置くことを期待したが、悲しいことに、このケースではありません。私はchmod 755データベースに試してみましたが、それはどちらか動作しませんでした

Thread 1: Fatal error: 'try!' expression unexpectedly raised an error: SQLite error 8 with statement UPDATE quotes SET favorite = 1 WHERE quote = ? arguments ["Abstinence is the great strengthener and clearer of reason."]: attempt to write a readonly database

:私はこのエラーを取得します。何か不足していますか?

答えて

2

データベースへのパスは、アプリケーションリソースへのパスです。 iOSではアプリリソースを変更できません。

詳細については、File System Basicsを参照してください。特に関連する見積もり:

[...] the app’s bundle. This directory contains the app and all of its resources.

You cannot write to this directory. To prevent tampering, the bundle directory is signed at installation time. Writing to this directory changes the signature and prevents your app from launching. You can, however, gain read-only access to any resources stored in the apps bundle. For more information, see the Resource Programming Guide .

ここで、変更できない場合、どのようにあなたのデータベースに書き込むのですか?

まあ、あなたはそれを変更できる場所にコピーします。バンドルされたデータベースリソースを変更することは決してなく、コピーを変更するだけです。

可能なドキュメントが再びあります:How do I open a database stored as a resource of my application? GRDBよくある質問はこう述べています。このコードの

If the application should modify the database resource, you need to copy it to a place where it can be modified. For example, in the Application Support directory. Only then, open a connection:

let fileManager = FileManager.default 

let dbPath = try fileManager 
    .url(for: .applicationSupportDirectory, in: .userDomainMask, appropriateFor: nil, create: true) 
    .appendingPathComponent("db.sqlite") 
    .path 

if !fileManager.fileExists(atPath: dbPath) { 
    let dbResourcePath = Bundle.main.path(forResource: "db", ofType: "sqlite")! 
    try fileManager.copyItem(atPath: dbResourcePath, toPath: dbPath) 
} 

let dbQueue = try DatabaseQueue(path: dbPath) 
+0

ありがとう。データベースが変更されたら、メインバンドルに変更を書き込むことは可能でしょうか?または、新しく追加されたデータを取得するためにDBに読み込もうとしても、同じプロセスを使用する必要があります。 –

+0

いいえ、リソースを変更することはできないため、メインバンドルに変更をコピーすることはできません。しかし、サンプルコードをより慎重に読んで理解してください。1.コピーがまだ存在しない場合にのみリソースデータベースをコピーし、次にコピーされた書き込み可能データベースを開きます。つまり、一意の初期コピーの後に実行された変更は、起動後も起動されたままになります。つまり、アプリケーションは変更をリソースデータベースのコピーで上書きしません。 –

+0

最後のコメント:アプリケーションにバンドルされているデータベースのコピーが1回だけ*発生するため、アプリが最終的に更新されるときに何が起こるのか不思議に思うかもしれません。新しいアプリケーションバージョンに同梱されている更新されたリソースデータベースは、以前のバージョンが既にコピーされているときはまったく使用されません。これがOKかどうかわかりません。それはあなたの特定のアプリに依存します。 OKでない場合は、ローカルの変更と将来のデータベースバージョンからの更新の両方を許可するための戦略を設計する必要があります。これはあまり簡単ではなく、まったく別の質問です。 –

関連する問題