RxSwift filter Variable array

Hola, estoy tratando de comprender la biblioteca RxSwift para escribir mejor el código funcional.

Actualmente estoy atrapado en un problema muy básico. Digamos que obtuve estas variables de tipo Variable<[CiteModel?]> :

 var allCites: Variable<[CiteModel?]> = Variable([]) var shownCites: Variable<[CiteModel?]> = Variable([]) 

Ahora quiero filtrar todas las citas de la matriz allCites que contienen un text específico y agregarlas a shownCites .

Esto es lo que he intentado pero no comstack porque dentro de mi bloque de filter $0 es [CiteModel?] No CiteModel? lo que espero ¿Podrías explicarme qué hice mal?

 private func filterCitesByQuery(query: String) { self.shownCites = self.allCites.asObservable().filter { $0?.cite.containsString(query) } } 

Error al ejecutar el código anterior:

 Cannot assign value of type 'Observable<[CiteModel?]>' (aka 'Observable<Array<Optional<CiteModel>>>') to type 'Variable<[CiteModel?]>' (aka 'Variable<Array<Optional<CiteModel>>>') 

map realiza una operación en cada uno de los valores de una secuencia . Al aplicar el map a un Observable<T> , el map recibirá T como un parámetro para su bloque.

En el caso de Variable<[CiteModel?]> , Observable es la secuencia de ahí T == [CiteModel?] .

Porque realmente queremos filtrar una matriz de [CiteModel?] , Puedes cambiar la definición de filterCitesByQuery a

 private func filterCitesByQuery(query: String) { // bag probably needs to be reset here allCites.asObservable() .map { // map: apply a transformation to $0 // The desinetworking transformation of $0 is to remove cite that do not contain query $0.filter { $0.cite.containsString(query) } } .bindTo(shownCites) .addDisposableTo(bag) } 

Pero este fragment sigue siendo subóptimo, ya que requiere una suscripción a todas las allCites a realizar, donde realmente no queremos observar sus cambios.

Una mejor implementación sería

 var allCites: Variable<[CiteModel?]> = Variable([]) var searchQuery: Variable<String> = Variable("") var shownCites: Observable<[CiteModel?]> = Observable .combineLatest(allCites.asObservable(), searchQuery.asObservable()) { allCites, query in return allCites.map { cites in cites.filter { $0.cite.containsString(query) } } } private func filterCitesByQuery(query: String) { searchQuery.value = query } 

Que está pasando aqui ?

combineLatest toma los últimos 2 valores conocidos de allCites y searchQuery . Cuando cualquiera de esos cambios, se ejecuta el bloque. Ahora podemos suscribirte a shownCites y obtendremos valores actualizados cada vez que cualquiera de los cambios fuente observables.

Lo conseguí trabajando con este código:

 private func filterCitesByQuery(query: String) { self.shownCites.value = self.allCites.value.filter { return $0?.cite.containsString(query) ?? false } } 

Sin embargo, todavía me gustaría saber cuál fue el error con el código original. Entonces, si alguien tiene una respuesta para mí, esto sería muy apreciado.

  //transform Variable to Observable allCites.asObservable() // Observable<[CiteModel?]> -> Observable<CiteModel?> .flatMap { $0.toObservable() } // $0?.containsString("query") is Optional, so I have to add ?? false. .filter { $0?.containsString("query") ?? false } // Observable<CiteModel?> -> Observable<[CiteModel?]> .toArray() // use bind (aka subscribe. Don't use .value of Variable) .bindTo(shownCites) .addDisposableTo(bag) 

Este código debería hacerlo por ti 🙂