Dependencia de RxSwift

May 02 2023
Si usó RxSwift, entonces está familiarizado con este fragmento de código: Para simplificar un poco este proceso y reducir la dependencia de RxSwift a un solo lugar, creo una clase simple siguiendo estos pasos. La lógica de disparar está dentro de la clase y puede dividir la lógica en una función separada.
Dependencia de RxSwift

Si ha utilizado RxSwift, entonces está familiarizado con este fragmento de código:

var taskChangeEvent = BehaviorSubject<Bool>()
...

if newValue != oldValue {
  subject.onNext(newValue)
}

...

taskChangeEvent.subscribe(onNext: { [weak self] done in
    ....
}).dispose(by: disposeBag)

Para simplificar un poco este proceso y reducir la dependencia de RxSwift a un solo lugar, creo una clase simple siguiendo estos pasos.

import RxSwift

class EventSerializer<T: Equatable> {
    private var disposeBag = DisposeBag()
    fileprivate let contactPoint: BehaviorSubject<T>
    var value: T

    func send(_ newValue: T) {
        contactPoint.onNext(newValue)
        self.value = newValue
    }
    func sendValueIf(_ newValue: T, compareWith: (_ oldValue: T, _ newValue: T) -> Bool) {
        if compareWith(self.value, newValue) {
            contactPoint.onNext(newValue)
            self.value = newValue
        }
    }
    func listen(onChange: @escaping ((T) -> Void)) {
        contactPoint.subscribe( onNext: { value in
            onChange(value)
        }).disposed(by: disposeBag)
    }
    init(defaultValue: T, contactPoint: BehaviorSubject<T>? = nil) {
        self.contactPoint = contactPoint ?? BehaviorSubject<T>(value: defaultValue)
        self.value = defaultValue
    }
}

La lógica de disparar está dentro de la clase y puede dividir la lógica en una función separada.

Escuchar la transmisión es mucho más limpio y no hay disposeBag en todo el código.

var task = EventSerilizer<Bool>(defaultValue: false)

...

func shouldInformTaskChange(_ oldValue: Bool, _ newValue: Bool) {
    oldValue != newValue
}
task.sendValueIf(true, compareWith: shouldInforTaskChange)

...

task.listen { [weak self] value in 
    ....
}

func listenToCombineLatest<E: Equatable>(with otherSerializer: EventSerializer<E>, onChange: @escaping ((T, E) -> Void)) {
    Observable.combineLatest(self.contactPoint, otherSerializer.contactPoint).subscribe(onNext: { tValue, eValue in
        onChange(tValue, eValue)
    }).disposed(by: disposeBag)
}

Una nota al margen sobre el uso de BehaviorSubject

Como sabes, el BehaviorSubject emite el último evento a quien comienza a escuchar. Esto podría ser un problema, durante la fase de configuración, ya que es como si estuviera haciendo cañerías mientras hay agua en las tuberías. Te visitan mientras aún no estás listo. Por otro lado, PublishSubject le permite conectar tuberías y luego envía los eventos.

Así que considere usar PublishSubject si necesita algo de tiempo de preparación antes de recibir eventos.