Subjects in RxSwift
This post hasn't been updated for 4 years
Subject trong RxSwift hoạt động như vừa là một Observable, vừa là một Observer. Khi một Subject nhận một .next event thì ngay lập tức nó sẽ phát ra các emit cho các subscriber của nó. Không chỉ vậy Subject còn được chia ra làm 4 loại: PublishSubject, BehaviorSubject, ReplaySubject, Variable với từng mục đích sử dụng. Chính vì những lý do như vậy nên Subject được sử dụng khá là phổ biến khi chúng ta làm việc với RxSwift.
Publish Subject
Publish subjects được sử dụng khi bạn chỉ muốn subscribers được thông báo về các sự kiện mới từ thời điểm bạn subscribe cho đến khi hủy subscribe hoặc Subject đã chấm dứt với sự kiện khi .completed hoặc .error. Hãy thử một ví dụ để hiểu rõ hơn về Publish Subject:
let bag = DisposeBag()
//khởi tạo một PublishSubject kiểu String
let publishSubject = PublishSubject<String>()
//Phát ra một emit với chuỗi String "Emit 1"
publishSubject.onNext("Emit 1")
//tạo ra một Subscriber để lắng nghe sự kiện từ subject
let subscriberOne = publishSubject.subscribe { element in
print("subscriber 1: \(element)")
}
subscriberOne.disposed(by: bag)
publishSubject.onNext("Emit 2") //Phát ra một emit với chuỗi String "Emit 2"
publishSubject.onNext("Emit 3") //Phát ra một emit với chuỗi String "Emit 3"
Lưu ý: Tất cả các subject khi đã terminate thì vẫn re-emit stop event cho các subscriber mới trong tương lai. Chúng ta có thể thấy rõ điều đó thông qua ví dụ sau
let bag = DisposeBag()
//khởi tạo một PublishSubject kiểu String
let publishSubject = PublishSubject<String>()
//Phát ra một emit với chuỗi String "Emit 1"
publishSubject.onNext("Emit 1")
//tạo ra một Subscriber để lắng nghe sự kiện từ subject
let subscriberOne = publishSubject.subscribe { element in
print("subscriber 1: \(element)")
}
subscriberOne.disposed(by: bag)
publishSubject.onNext("Emit 2") //Phát ra một emit với chuỗi String "Emit 2"
publishSubject.onNext("Emit 3") //Phát ra một emit với chuỗi String "Emit 3"
publishSubject.onCompleted() //terminate Subject
//tạo ra một Subscriber mới
let subscriberTwo = publishSubject.subscribe { element in
print("subscriber 2: \(element)")
}
subscriberTwo.disposed(by: bag)
Kết quả in ra sẽ là:
subscriber 1: next(Emit 2)
subscriber 1: next(Emit 3)
subscriber 1: completed
subscriber 2: completed
Chúng ta có thể thấy là subscriber 2 đã lắng nghe sau khi publish subject emit sự kiện complete nhưng vẫn có thể lắng nghe được.
BehaviorSubject
BehaviorSubject hoạt động tương tự như PublishSubject, nhưng chỉ khác ở chỗ BehaviorSubject khởi đầu với một giá trị và replay lại giá trị đó hoặc .next event cuối cùng của observable cho một Subscriber mới. Hãy cũng tìm hiểu ví dụ sau:
let bag = DisposeBag()
//Khởi tạo một BehaviorSubject kiểu String với giá trị ban đầu là "Initial Value"
let behaviorSubject = BehaviorSubject<String>(value: "Initial Value")
//Phát ra một emit với giá trị "Emit 1"
behaviorSubject.onNext("Emit 1")
print("- Subscribe here -")
let subscriber = behaviorSubject.subscribe { element in
print("Subscriber: \(element)")
}
subscriber.disposed(by: bag)
behaviorSubject.onNext("Emit 2")
behaviorSubject.onNext("Emit 3")
Chúng ta thu được kết quả
Subscriber: next(Emit 1)
Subscriber: next(Emit 2)
Subscriber: next(Emit 3)
Subscriber vẫn nhận được "Emit 1" bởi tại thời điểm nó subscribe thì "Emit 1" chính là element cuối cùng trong Observable của subject nên subject đã replay lại element này cho subscriber.
ReplaySubject
Được khởi tạo với một kích thước bộ đệm và sẽ chứa số lượng các emit gần nhất bằng với kích thước bộ đệm đã khai báo. ReplaySubject sẽ replay lại tất cả các emit trong bộ đệm cho subscriber ngay khi subscriber đăng ký. Nó giống với Behavior Subject nhưng thay vì chỉ có thể lưu trữ event cuối cùng để bắn cho subscriber mới thì ReplaySubject có buffer size - số lượng event lưu trữ để bắn lại chó subscriber mới.
let bag = DisposeBag()
//khởi tạo một ReplaySubject kiểu String với size của buffer là 2
let replaySubject = ReplaySubject<String>.create(bufferSize: 2)
replaySubject.onNext("Emit 1") //Phát ra một emit với String "Emit 1"
replaySubject.onNext("Emit 2") //Phát ra một emit với String "Emit 2"
replaySubject.onNext("Emit 3") //Phát ra một emit với String "Emit 3"
print("- Before subscribe -")
//tạo ra một Subscriber để lắng nghe sự kiện từ replaySubject
let subscriber = replaySubject.subscribe { element in
print("Subscriber: \(element)")
}
subscriber.disposed(by: bag)
print("- After subscribe -")
replaySubject.onNext("Emit 4")
replaySubject.onNext("Emit 5")
Kết quả sẽ là:
- Before subscribe -
Subscriber: next(Emit 2)
Subscriber: next(Emit 3)
- After subscribe -
Subscriber: next(Emit 4)
Subscriber: next(Emit 5)
Variable
Lưu trữ dữ liệu hiện tại của BehaviorSubject như một state và replay duy nhất giá trị khởi tạo hoặc giá trị cuối cùng của dữ liệu cho subscriber mới.
let bag = DisposeBag()
//Khởi tạo một Variable với giá trị khởi tạo là "Initial Value"
let variableSubject = Variable("Initial Value")
let subscriber = variableSubject.asObservable()
.subscribe { value in
print("Subscriber: \(value)")
}
subscriber.disposed(by: bag)
variableSubject.value = "New value"
Kết quả:
Subscriber: next(Initial Value)
Subscriber: next(New value)
Kết luận & Tài liệu tham khảo
Như vậy mình đã giới thiệu về các loại subject cơ bản, mục đích và cách sử dụng chúng. Mong sẽ giúp đỡ các bạn trong viẹc tìm hiểu về RxSwift.
Refs: RxSwift: Reactive Programming with Swift by the raywendrich.com Tutorial Team
All Rights Reserved