Phụ thuộc RxSwift

May 02 2023
Nếu bạn đã sử dụng RxSwift thì bạn đã quen thuộc với đoạn mã này: Để làm cho quy trình này đơn giản hơn một chút và giảm sự phụ thuộc của RxSwift vào một nơi duy nhất, tôi xây dựng một lớp đơn giản chỉ cần thực hiện các bước này. Logic kích hoạt nằm trong lớp và bạn có thể chia logic thành một chức năng riêng biệt.
Phụ thuộc RxSwift

Nếu bạn đã sử dụng RxSwift thì bạn đã quen thuộc với đoạn mã này:

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

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

...

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

Để làm cho quy trình này đơn giản hơn một chút và giảm sự phụ thuộc vào RxSwift vào một nơi duy nhất, tôi xây dựng một lớp đơn giản chỉ cần thực hiện các bước này.

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
    }
}

Logic kích hoạt nằm trong lớp và bạn có thể chia logic thành một chức năng riêng biệt.

Nghe luồng trực tuyến sạch hơn nhiều và không có discardBag trên toàn bộ mã.

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)
}

Một lưu ý phụ về việc sử dụng BehaviorSubject

Như bạn đã biết, BehaviorSubject đưa ra sự kiện cuối cùng mà ai bắt đầu lắng nghe. Đây có thể là một vấn đề, trong giai đoạn thiết lập, bởi vì nó giống như hệ thống ống nước khi có nước trong đường ống. Bạn được viếng thăm trong khi bạn chưa sẵn sàng. Mặt khác, PublishSubject cho phép bạn kết nối các đường ống với nhau và sau đó gửi các sự kiện.

Vì vậy, hãy cân nhắc sử dụng PublishSubject nếu bạn cần một chút thời gian chuẩn bị trước khi nhận sự kiện.