Search code examples
swiftswift3realmrx-swiftrxdatasources

Unable to filter objects with RxSwift/RxRealm


I am new to reactive programming and I am experiencing difficulty in filtering and accessing object from a specific index. Below is my code snippet.

    private var contacts: Observable<(AnyRealmCollection<Contact>, RealmChangeset?)>!

        override func viewDidLoad() {
            super.viewDidLoad()

            contacts = Observable.changeset(from: contactViewModel.getDeviceContacts())
            let dataSource = RxCollectionViewRealmDataSource<Contact>(cellIdentifier: "SendFeedContactCell", cellType: ContactCollectionCell.self) {cell, ip, contact in
                cell.configure(contact)
            }

            contacts
                .bindTo(collectionView.rx.realmChanges(dataSource))
                .addDisposableTo(disposeBag)

            searchBar
                .rx.text
                .orEmpty
                .subscribe(onNext: { [unowned self] query in
                    // Filter query - doesn't work!
                    // self.contacts.filter({ (observable) -> Bool in
                    // observable.0.filter(NSPredicate(format: "name CONTAINS[c] '\(query)'"))
                    // })
                })
                .addDisposableTo(disposeBag)  

            collectionView.rx.itemSelected
            .subscribe(onNext: { indexPath in
                // TODO: How to access a specific object from the contacts object
            })
            .addDisposableTo(disposeBag)
        }
  1. I am receiving query in the search bar but filtering doesn't seems to work.

  2. I am getting IndexPath when an item is selected in the collection view but I am wondering how I can access a specific model properties based on the index path.

I am using RxRealm and RxRealmDataSources as my data is stored in realm database in device.


Solution

  • 1) Regarding your first question: you cannot imperatively filter an observable. You are trying to use it as an array, but an observable does not have a "value" you can filter at arbitrary times. To filter the collection you are binding to your table view, you need to filter the realm results that is the source of your contacts observable.

    E.g. you need to re-create the contacts observable, and bind this new observable to your table view.

    There is a somewhat similar (but not exact) example of how to filter a table view with Rx here: https://realm.io/news/marin-todorov-realm-rxswift/.

    2) You are using rx.itemSelected which gives you an index path. As said above, an Observable isn't an array that you can access in arbitrary ways, so what you want to do is not possible. You can use rx.modelSelected instead, which will give you directly the corresponding object (instead of the index path). You can see more about modelSelected here: https://github.com/ReactiveX/RxSwift/blob/master/RxCocoa/iOS/UICollectionView%2BRx.swift#L231