使用 Sqlite 和 GRDB 的 SwiftUI FileDocument

SwiftUI FileDocument using Sqlite and GRDB

在基于文档的 SwiftUI 应用程序中,我想使用 GRDB 作为 Sqlite 包装器将每个文档保存到一个单独的 Sqlite 文件中。通过为要加载的文件创建一个 DatabaseQueue 并使用其 .backup(to:) 方法复制到内存中 DatabaseQueue。我应该如何在func fileWrapper(configuration: WriteConfiguration) 方法中实现保存?似乎没有明显的方法可以使用相同的 .backup(to:) 方法。

我找到了 Andre Yonadam 的 example application,它在 NSDocument 的子类中以相同的方式解决了这个问题:

override func write(to url: URL, ofType typeName: String, for saveOperation: NSDocument.SaveOperationType, originalContentsURL absoluteOriginalContentsURL: URL?) throws {
    let destination = try DatabaseQueue(path: url.path)
    do {
        try memoryDBQueue.backup(to: destination)
    } catch {
        throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
    }
}

override func read(from url: URL, ofType typeName: String) throws {
    let source = try DatabaseQueue(path: url.path)
    do {
        try source.backup(to: memoryDBQueue)
    } catch {
        throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
    }
}

这可能不是最干净的解决方案,但我通过实现知道如何写入 Sqlite 文件的 FileWrapper 子类解决了这个问题:

class SqliteFileWrapper: FileWrapper {

    var databaseQueue: DatabaseQueue

    init (fromDatabaseQueue databaseQueue: DatabaseQueue) {
        self.databaseQueue = databaseQueue
        super.init(regularFileWithContents: "".data(using: .utf8)!)
    }

    required init?(coder inCoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func write(
        to url: URL,
        options: FileWrapper.WritingOptions = [],
        originalContentsURL: URL?
    ) throws {
        let destination = try DatabaseQueue(path: url.path)
        do {
            try databaseQueue.backup(to: destination)
        } catch {
            throw NSError(domain: NSOSStatusErrorDomain, code: unimpErr, userInfo: nil)
        }
    }

}

然后在我的 FileDocument 子类中创建一个 SqliteFileWrapper 而不是 FileWrapper:

func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
    SqliteFileWrapper(fromDatabaseQueue: memoryDBQueue)
}