Reputation: 4355
Following a similar example to question 39 here: http://reactivex.io/learnrx/
I'm trying to transform a method call search(query: String)
into a sequence of those calls.
They way I'm achieving this is by creating a Variable
which I update with the query
value every time
the search(query: String)
method is called.
Then I have this in my init()
:
_ = queryVariable.asObservable().flatMap({ query -> Observable<[JSON]> in
return self.facebookSearch(query).takeUntil(self.queryVariable.asObservable())
}).subscribeNext({ result in
if let name = result[0]["name"].string {
print(name)
} else {
print("problem")
}
})
If I type "ABC"
, my search(query: String)
method will be called 3 times with "A"
, "AB"
, "ABC"
.
That would be mapped to seq(["A", "AB", "ABC"])
with queryVariable.asObservable()
.
Then I'm mapping it to Facebook searches (searching people by their names on Facebook).
And with subscribeNext
I print the name.
If I don't use the takeUntil
, it works as I'd expect, I get 3 sets of results, one for each of my queries("A"
, "AB"
, "ABC"
).
But if I type fast (before Facebook has time to respond to the request), I'd want only one result, for the query "ABC"
. That's why I added the takeUntil
. With it I'd expect the facebookSearch(query: String)
call to be ignored when the next query
comes in, but it is being canceled for the current query, so with this takeUntil
I end up printing nothing.
Is this a known issue or am I doing something wrong?
Upvotes: 2
Views: 3381
Reputation: 27620
I used your code and found two solutions to your problem:
1. Use flatMapLatest
You can just use flatMapLatest
instead of flatMap
and takeUntil
. flatMapLatest
only returns the results of the latest search request and cancels all older requests that have not returned yet:
_ = queryVariable.asObservable()
.flatMapLatest { query -> Observable<String> in
return self.facebookSearch(query)
}
.subscribeNext {
print($0)
}
2. Use share
To make your approach work you have to share the events of your queryVariable
Observable when you also use it for takeUntil
:
let queryObservable = queryVariable.asObservable().share()
_ = queryObservable
.flatMap { query -> Observable<String> in
return self.facebookSearch(query).takeUntil(queryObservable)
}
.subscribeNext {
print($0)
}
If you do not share the events, the searchQuery.asObservable()
in takeUntil
creates its own (duplicate) sequence. Then when a new value is set on the searchQuery
Variable it immediately fires a Next event in the takeUntil() sequence and that cancels the facebookSearch results.
When you use share()
the sequence in takeUntil
is observing the same event as the other sequence and in that case the takeUntil
sequence handles the Next event after the facebookSearch has returned a response.
IMHO the first way (flatMapLatest) is the preferred way on how to handle this scenario.
Upvotes: 3