Khái niệm
Thay vì bạn phải cất công create hay subcribe đầy đủ các sự kiện mà 1 Observable phát ra. Bạn có thể tạo ra các Observable đặc biệt và đơn thuần thôi. RxSwift gọi là Trait.
- Trait là một wrapper struct với một thuộc tính là một Observable Sequence nằm bên trong nó. Trait có thể được coi như là một sự áp dụng của Builder Pattern cho Observable.
- Để chuyển Trait về thành Observable, chúng ta có thể sử dụng operator .asObservable()
- Traits sẽ chỉ thực hiện một nhiệm vụ cụ thể nào đó mà thôi.
Các đặc điểm của Trait bao gồm:
- Nó không xảy ra lỗi.
- Trait được observe và subscribe trên MainScheduler.
- Trait không chia sẻ Side Effect. (một số loại khác sẽ có) Side Effect là những thay đổi phía bên ngoài của một scope (khối lệnh). Trong RxSwift, Side Effect được dùng để thực hiện một tác vụ nào đó nằm bên ngoài của scope mà không làm ảnh hưởng tới scope đó.
Chúng ta có 2 loại Trait, một cái cho RxSwift và một cái RxCocoa. Traits trong RxSwift thì sẽ có 3 loại:
- Single
- Completable
- Maybe
1. Single
- Single là một biến thể của Observable trong RxSwift.
- Thay vì emit được ra một chuỗi các element như Observable thì Single sẽ chỉ emit ra duy nhất một element hoặc một error.
- Không chia sẻ Side Effect.
Ví dụ:
enum FileError: Error { case pathError } let bag = DisposeBag() func readFile(path: String?) -> Single<String> { return Single.create { single -> Disposable in if let path = path { single(.success("Success!")) } else { single(.error(FileError.pathError)) } return Disposables.create() } }
Function readFile có giá trí trả về là 1 Single với kiểu Output là String. Vì Single cũng là 1 Observable, nên ta lại áp dụng toán tử .create để tạo. Và quan trọng là handle các thao tác trong đó (lúc nào là error hay giá trị ….).
cách subscribe:
readFile(path: nil) .subscribe { event in switch event { case .success(let value): print(value) case .error(let error): print(error) } } .disposed(by: bag)
Ta sẽ switch ... case được giá trị mà Single trả về. Với 2 trường hợp.
Có thể biến 1 Observable thành một Single bằng toán tử .asSingle(). Được ứng dụng RxSwift vào trong các Model gọi API rồi đó. Cách gọi hay hơn là các call back.
2. Completable
- Giống với Single, Completable cũng là một biến thể của Observable.
- Điểm khác biệt của Completable so với Single, đó là nó chỉ có thể emit ra một error hoặc chỉ complete (không emit ra event mà chỉ terminate).
- Không chia sẻ Side Effect.
Ví dụ:
let bag = DisposeBag() enum FileError: Error { case pathError case failedCaching } func cacheLocally() -> Completable { return Completable.create { completable in // Store some data locally //... //... let success = true guard success else { completable(.error(FileError.failedCaching)) return Disposables.create {} } completable(.completed) return Disposables.create {} } }
Function cacheLocally trả về một kiểu Completable. Và áp dụng cách tương tự như Single, thì sử dụng .create để tạo một Observabe Completable và hành vi cho nó. Cách sử dụng cũng tương tự như trên.
Cách subscribe. Cách 1:
cacheLocally() .subscribe { completable in switch completable { case .completed: print("Completed with no error") case .error(let error): print("Completed with an error: \(error)") } } .disposed(by: bag)
Cách 2:
cacheLocally() .subscribe(onCompleted: { print("Completed with no error") }, onError: { error in print("Completed with an error: \(error)") }) .disposed(by: bag)
3. MayBe
- Maybe cũng là một biến thể của Observable và là sự kết hợp giữa Single và Completable.
- Nó có thể emit một element, complete mà không emit ra element hoặc emit ra một error.
- Có thể phát ra duy nhất một element, phát ra một error hoặc cũng có thể không phát ra bất cứ event nào và chỉ complete.
- Sau khi thực hiện bất kỳ 1 trong 3 sự kiện nêu trên thì Maybe cũng sẽ terminate.
- Không chia sẻ Side Effect.
Ví dụ:
let bag = DisposeBag() enum MyError: Error { case anError } func generateString() -> Maybe<String> { return Maybe<String>.create { maybe in maybe(.success("RxSwift")) // OR maybe(.completed) // OR maybe(.error(MyError.anError)) return Disposables.create {} } }
Về Maybe , tương tự như 2 cái trên về cách tạo và xử lý. Nó có thể phát đi cái gì cũng đc, linh hoạt hơn. Dùng cho cách xử lý mà có thể trả không cần phát đi gì cả hoặc kết thúc.
Cách subscribe như sau: Cách 1:
generateString() .subscribe { maybe in switch maybe { case .success(let element): print("Completed with element \(element)") case .completed: print("Completed with no element") case .error(let error): print("Completed with an error \(error.localizedDescription)") } } .disposed(by: bag)
Cách 2:
generateString() .subscribe(onSuccess: { element in print("Completed with element \(element)") }, onError: { error in print("Completed with an error \(error.localizedDescription)") }, onCompleted: { print("Completed with no element") }) .disposed(by: bag)
Bạn có thể dùng toán tử .asMayBe() để biến 1 Observable thành 1 Maybe.
Tham khảo: https://fxstudio.dev/rxswift-traits/