【问题标题】:Swift GRDB Writing to Database Error "attempt to write a readonly database"Swift GRDB 写入数据库错误“尝试写入只读数据库”
【发布时间】:2018-05-23 21:15:08
【问题描述】:

我正在尝试写入我创建的报价数据库。如果用户选择“收藏”按钮,它将在 SQLITE 数据库的收藏列中添加一个 1(或真)值。由于某种原因,我无法写入数据库,当我执行此代码时:

    @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,但遗憾的是事实并非如此。我收到此错误:

线程 1:致命错误:“尝试!”表达式意外引发错误:SQLite error 8 with statement UPDATE quotes SET favorite = 1 WHERE quote = ? arguments ["Abstinence is the greatstrengthener and clearer of reason."]: 尝试编写只读数据库

我曾尝试chmod 755 数据库,但也没有用。我错过了什么吗?

【问题讨论】:

    标签: swift database sqlite grdb


    【解决方案1】:

    数据库路径是应用程序资源的路径。无法在 iOS 中修改应用资源。

    请参阅File System Basics 了解更多信息。特别相关的引述:

    [...] 应用程序包。此目录包含应用程序及其所有资源。

    您无法写入此目录。为防止篡改,捆绑目录在安装时进行签名。写入此目录会更改签名并阻止您的应用程序启动。但是,您可以获得对存储在应用程序包中的任何资源的只读访问权限。如需更多信息,请参阅Resource Programming Guide

    现在,如果无法修改,如何在数据库中写入?

    好吧,你把它复制到你可以修改的地方。您永远不会修改捆绑的数据库资源,而只会修改副本。

    又有可用的文档:How do I open a database stored as a resource of my application?GRDB 常见问题解答说:

    如果应用程序要修改数据库资源,您需要将其复制到可以修改的地方。例如,在应用程序支持目录中。只有这样,打开一个连接:

    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)
    

    【讨论】:

    • 感谢您提供此代码。修改数据库后,是否可以将更改写入主包?或者即使尝试读取数据库以获取新添加的数据,我是否也必须使用相同的过程。
    • 不,因为您永远无法将更改复制到主包,因为永远无法修改资源。但是更仔细地阅读示例代码,并尝试理解它:它 1. 当且仅当副本尚不存在时,才复制资源数据库,然后 2. 打开复制的可写数据库。这意味着在唯一初始副本之后执行的更改将在启动后保持启动:应用不会用资源数据库的副本覆盖更改。
    • 最后一条评论:由于与应用程序捆绑在一起的数据库副本只发生一次,人们可能想知道当您的应用程序最终更新时会发生什么。新版应用程序附带的更新资源数据库在其先前版本已被复制时将根本不会使用。我不知道这是否可以。这取决于您的特定应用程序。如果不行,那么您将不得不设计一种策略来允许本地修改和未来数据库版本的更新。这不那么琐碎,完全是另一个问题。
    • 将内容保存到核心数据中会不会很聪明?将保存的数据是一组收藏的引号。
    猜你喜欢
    • 2016-10-20
    • 2015-10-27
    • 2017-09-27
    • 2021-09-11
    • 2021-03-02
    • 1970-01-01
    • 1970-01-01
    • 2016-08-16
    • 2017-07-17
    相关资源
    最近更新 更多