-
Notifications
You must be signed in to change notification settings - Fork 276
Description
Let's take the sample code from the readme:
let realm = try! Realm()
let laps = realm.objects(Lap.self)
Observable.changeset(from: laps)
.subscribe(onNext: { results, changes in
if let changes = changes {
// it's an update
print(results)
print("deleted: \(changes.deleted)")
print("inserted: \(changes.inserted)")
print("updated: \(changes.updated)")
} else {
// it's the initial data
print(results)
}
})
The above code sets synchronousStart to true by default.
Here is the implementation of Observable.changeset(from: synchronousStart)
:
public static func changeset(from collection: E, synchronousStart: Bool = true)
-> Observable<(AnyRealmCollection<E.ElementType>, RealmChangeset?)> {
return Observable.create { observer in
if synchronousStart {
observer.onNext((collection.toAnyCollection(), nil))
}
let token = collection.toAnyCollection().observe { changeset in
switch changeset {
case .initial(let value):
guard !synchronousStart else { return }
observer.onNext((value, nil))
case .update(let value, let deletes, let inserts, let updates):
observer.onNext((value, RealmChangeset(deleted: deletes, inserted: inserts, updated: updates)))
case .error(let error):
observer.onError(error)
return
}
}
return Disposables.create {
token.invalidate()
}
}
}
If the database is modified continuously from a background thread it can happen that the database changes in between invoking code observer.onNext((collection.toAnyCollection(), nil))
and guard !synchronousStart else { return }
. As a result one change is swallowed and the next change that is delivered by observer.onNext((value, RealmChangeset(deleted: deletes, inserted: inserts, updated: updates)))
will be incompatible with the previously saved state of the collection in the view model.
Because of the lost/swallowed change of the collection the incremental update of UITableView will crash the app if the change to be applied is not valid. (Invalid update, etc)
The current workaround for me is to set _ synchronousStart_ to false.
So, basically synchronous start with the current implementation does not work in some situation.