I’m trying to setup following background service:
- realm db to store reports
- observe realm for closed reports and send them to server
- this should all be done on bg thread (e.g. DispatchQueue(qos: .background))
func sendReports() {
observe(RealmReport.self, predicate: .init(format: "state == %@", .closed)
.receive(on: DispatchQueue(label: "report-sender")
.sink { report in
self.send(report: report) // makes API call
}
.store(in: &subscriptions) // keep observing as long as app is alive
}
func observe(_ type: Object.Type, predicate: NSPredicate) -> AnyPublisher<[Report], Error> {
Just((type, predicate))
.receive(on: DispatchQueue.main) // should be on bg queue, but realm publisher needs runloop, I guess?
.flatMap { objectType, predicate in
self.realm().objects(objectType) // Realm instance is kept alive til app is killed
.filter(predicate)
.collectionPublisher
// .threadSafeReference() // send live objects, heavy
// .freeze() // lightweight; snapshot of live objects to pass to other threads, but version is cached in file until Realm instance is gone?
.map(\.elements)
}
.tryMap { $0.map { Report(from: $0) } }
.mapError { _ in
Error.dbError
}
.eraseToAnyPublisher()
}
I found some problems:
-
.freeze()
is preferred to be used with Combine,
but is it increasing active versions?
I saw: - assert due to max number of active versions
- realm accessed from wrong thread
sometimes