Методы доступа к базе данных GRDB не являются реентерабельными (методы чтения и записи в DatabaseQueue и DatabasePool).
Чтобы помочь вам решить проблему, попробуйте разделить методы доступа к базе данных на два уровня.
Первый уровень не доступен для остальной части приложения. Все его методы принимают аргумент db: Database
.
class MyStack {
private var dbQueue: DatabaseQueue
private func fetchFoo(_ db: Database, id: Int64) throws -> Foo? {
return try Foo.fetchOne(db, key: id)
}
private func setBar(_ db: Database, foo: Foo) throws {
try foo.updateChanges(db) {
$0.bar = true
}
}
}
Методы второго уровня доступны для остальной части приложения. Они заключают в себе методы первого уровня в read
и write
методах доступа к базе данных:
class MyStack {
func fetchFoo(id: Int64) throws -> Foo? {
return try dbQueue.read { db in
try fetchFoo(db, id: id)
}
}
func setBar(id: Int64) throws {
try dbQueue.write { db in
guard let foo = try fetchFoo(db) else {
throw fooNotFound
}
try setBar(foo: foo)
}
}
}
Методы первого уровня могут быть настолько низкими, насколько это необходимо, и могут быть составлены .
Методы второго уровня являются высокоуровневыми и не поддаются компоновке: они не могут вызывать друг друга из-за фатальной ошибки «Соединения с базой данных не реентерабельные». Они предоставляют поточно-ориентированные методы базы данных, которые гарантируют согласованность базы данных.
Для получения дополнительной информации см. Руководство по параллелизму .