I'm trying to implement user-driven refreshing in my Rx based networking code, and my current design is as follows:
- Create a sink that has
Void
values passed into it every time the user initiates a refresh action flatMap
the latest.Next
event on that sink'sObservable
into a new network call- Transform the network response into a new view model and pass that back into the view controller
The part I'm getting hung up on is how to create a sink for those events to go down. My current code is as follows:
func contactListModel() -> Observable<ContactListViewModel<Contact>> {
// Create a sink for refresh events
var refreshSink: AnyObserver<Void> = AnyObserver { event in }
let refreshObservable = Observable<Void>.create { observer in
refreshSink = observer
return NopDisposable.instance
}
// Define action handlers
let searchClosure = { (query: String?) in
self.contactsSearchTerm.value = query
}
let refreshClosure = refreshSink.onNext
// TODO: [RP] Make contact list view controller handle a nil view model to remove the need for this code
let initialViewModel = ContactListViewModel<Contact>(contacts: [], searchClosure: searchClosure, refreshClosure: refreshClosure)
// Perform an initial refresh
defer {
refreshSink.onNext()
}
// Set up subscription to push a new view model each refresh
return refreshObservable
.flatMapLatest {
return self.networking.request(.ListContacts)
}
.mapToObject(ListContactsResponse)
.map { response in
return ContactListViewModel(contacts: response.contacts, searchClosure: searchClosure, refreshClosure: refreshClosure)
}
.startWith(initialViewModel)
}
Now it's obvious why my code to create an event sink doesn't work here. The block being passed into refreshObservable
's create
method is only called once the observer is subscribed to, so the refreshSink
won't be reassigned until then. Furthermore, if this observable is subscribed to more than once, the refreshSink
variable will be reassigned.
So my question is this: how do I create an Observable
that I can manually push events down? Or alternatively, is there a better design I could be using here?
I know ReactiveCocoa has the pipe
static method on Signal
that will do something like what I'm looking for, but I've found no equivalent in the Rx API.