2016-03-23 3 views
3

Привет, Я пытаюсь понять библиотеку RxSwift, чтобы лучше писать функциональный код.RxSwift filter Переменный массив

В настоящее время я застрял в очень простой проблеме. Допустим, я получил это переменные типа Variable<[CiteModel?]>:

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

Теперь я хочу, чтобы фильтровать все цитирует из allCites массива, которые содержат определенный текст и добавить их в shownCites.

Это то, что я пытался, но он не компилируется, потому что внутри моего блока $0 фильтрующей [CiteModel?]неCiteModel?, что я бы ожидать. Не могли бы вы объяснить мне, что я сделал не так?

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

Ошибка при выполнении приведенного выше кода:

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

Откуда эта информация? Я не смог найти документацию по классу Variable. – dehlen

+0

Да, я обновил вопрос с ошибкой, которую я сейчас получаю. – dehlen

ответ

6

map выполняет операцию по каждым значениям последовательности. При применении map к Observable<T>, map получит T в качестве параметра к своему блоку.

В случае Variable<[CiteModel?]>, Observable является последовательность поэтому T == [CiteModel?].

Потому что мы действительно хотим, чтобы фильтровать массив [CiteModel?], вы можете изменить определение filterCitesByQuery к

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

Но этот фрагмент еще неоптимальной, так как она требует подписки на allCites должны быть сделаны, где мы действительно не хотим наблюдать за его изменениями.

Лучше реализация будет

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 
} 

Что здесь происходит?

combineLatest принимает последние 2 известных значения allCites и searchQuery. При любом из этих изменений блок выполняется. Теперь мы можем подписаться на shownCites и получать обновленные значения каждый раз при изменении исходных наблюдаемых изменений.

+0

Ничего себе, что отличный ответ. Это делает его намного понятнее, и для меня это выглядит как правильный способ сделать это, поэтому я буду отмечать это как принятое. благодаря – dehlen

1

Я получил это работает с этим кодом:

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

Однако я все же хотел бы знать, что было неправильно с оригиналом код. Поэтому, если у кого-то есть ответ для меня, это будет действительно оценено.

1
//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 (a.k.a. subscribe. Don't use .value of Variable) 
     .bindTo(shownCites) 
     .addDisposableTo(bag) 

Этот код должен сделать это для вас :)

+0

Спасибо, гораздо больше, чем RxSwift, чем моя версия. – dehlen

Смежные вопросы