Search code examples
iosswiftrx-swift

RxSwift filter Observable variable for UICollectionView numberOfItems(: )


I am a beginner in ReactiveSwift I have a UICollectionView. My aim is to filter / edit the Observable array of the UICollectionView. After getting no results with filtering, I print it out after trying to filter, the filter count is correct but there's a type mistake I guess.

items >>  RxSwift.(unknown context at $1024d7ea8).Map<Swift.Array<ReactiveThings.AnotherController.Element>, Swift.Array<ReactiveThings.AnotherController.Element>>

These are output.

    DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) {
        
        let items = observableElement.asObservable().map { element in
            element.filter {
                $0.age > 15
            }
        }
        
        print("items >> ", items)
        
    }

Here are my code.

import UIKit
import RxSwift
import RxCocoa

public final class AnotherController: UIViewController, UICollectionViewDelegateFlowLayout {

let disposeBag = DisposeBag()

var collectionView: UICollectionView = {
    let layout = UICollectionViewFlowLayout()
    var cv = UICollectionView.init(frame: .zero, collectionViewLayout: layout)
    cv.translatesAutoresizingMaskIntoConstraints = false
    return cv
}()

private func setup() {
    
    view.addSubview(collectionView)
    collectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
    collectionView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
    collectionView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
    collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    
    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "CustomCelly")
    
    collectionView.rx.setDelegate(self).disposed(by: disposeBag)
    

    var observableElement = Observable.just(elementArray)
    
    
    observableElement.bind(to: collectionView.rx.items(cellIdentifier: "CustomCelly")) { _, eleman, cell in
        if let cellToUse = cell as? UICollectionViewCell {
            cellToUse.backgroundColor = .red
        }
    }.disposed(by: disposeBag)
    
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) {
        
        let items = observableElement.asObservable().map { element in
            element.filter {
                $0.age > 15
            }
        }
        
        print("items >> ", items)
        
    }
    
    
    
}

struct Element {
    let name: String
    let age: Int
}

var elementArray = [
    Element.init(name: "E0", age: 15),
    Element.init(name: "E1", age: 12),
    Element.init(name: "E2", age: 13),
    Element.init(name: "E3", age: 14),
    Element.init(name: "E4", age: 17),
    Element.init(name: "E5", age: 18)
]


public override func viewDidLoad() {
    super.viewDidLoad()
    
    setup()
}

public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: UIScreen.main.bounds.width, height: 100)
}

I want to achieve manipulate the data after an action for example after a UIButton click, the count of the model array may reduce 3 from 6.

Thanks in advance


Solution

  • There's no type mistake. You are printing out the Observable itself, not the values that the Observable emits. So what you see in the print output is the description of the Observable.

    All you need to achieve what you want is:

    let observableElement = button.rx.tap
        .map { [elementArray] in
            elementArray.filter { $0.age > 15 }
        }
        .startWith(elementArray)
    

    To do anything more elaborate, you will probably want to use the scan operator to setup a state machine.

    To print out the values that your Observable emits, use the debug operator:

    observableElement
        .map { element in
            element.filter { $0.age > 15 }
        }
        .debug("items >>")
        .subscribe()