Thank you for noticing this mistake. You are correct than no changing the number of checked items doesn’t produce updated statistics when you add a new TODO.
The change you suggest is a good solution. The reason for zip not working is an optimization provided by Realm: when you filter a Realm collection, you are not merely using the Swift filter operator. You are using Realm’s version of filter which applies a predicate to the changes then emits appropriate changesets.
Inserting a new item doesn’t change the number of checked items, which is what the filter is looking at. Therefore, and since you don’t get a change, the zip operator patiently waits for the todoTasks sequence to emit something, which happens only when an items is checked or unchecked (due to the aforementioned optimization).
Using combineLatest is a correct way to fix this problem. At least one of the sequences will emit on item insert / delete (the tasks sequence) and trigger the production of a statistics update:
let tasks = realm.objects(TaskItem.self)
let todoTasks = tasks.filter("checked != nil")
return .combineLatest(
Observable.collection(from: tasks)
.map { $0.count },
Observable.collection(from: todoTasks)
.map { $0.count }) { all, done in
(todo: all - done, done: done)
}
Keeping zip is possible, if you base both sequences off the tasks sequence then further filter the results after tasks emits something:
let tasks = realm.objects(TaskItem.self)
return .zip(
Observable.collection(from: tasks)
.map { $0.count },
Observable.collection(from: tasks)
.map { $0.filter("checked != nil").count }) { all, done in
(todo: all - done, done: done)
}
The combineLatest solution is possible slightly more efficient since the other one has to further recreate filtered results, possibly eliminating internal optimizations that Realm may provide.
Congratulations on taking up the challenge so seriously as to beat the authors to their own challenges!