1. RxSwift profile

  • The role of RxSwift

1) When writing codes, we often need to detect changes of some values (such as textFiled input value changes, data request completion or failure changes) and process them accordingly. In the past, different event-passing methods were used for different situations, such as Delegate, notification, target-Action, KVO, etc. The appearance of RectiveX mechanism (implemented by RxSwift) unify the event passing response method in the program. Replace the usual event-passing methods (delegate, notification, target-Action, etc.) with Rx’s “signal chain” approach. (2) If we usually use MVVM development mode, through RxSwift can obtain more convenient data binding method, making MVVM development more powerful.

  • RxSwift and RxCocoa

RxSwift: It is based only on the Rx standard implementation library of the Swift language, so RxSwift does not contain any Cocoa or UI classes. RxCocoa: A library developed for iOS based on RxSwift that adds Rx features to native UI controls via Extension, making it easier to subscribe to and respond to their events.

Swift Books download:Download address

2. Simple use of RxSwift

2.1 Comparison sample between responsive programming and traditional programming

  • Example 2.1
  1. There is a requirement: the table is showing the song information (song name, and artist) click on any cell, print out the corresponding song information in the console.

  1. In the traditional way, first we create a Music structure that holds the name of the song and the name of the artist. It also follows the CustomStringConvertible protocol to facilitate debugging of output.
Import UIKit // struct Music {let name: String // let singer: String // String) {self.name = name self.singer = singer}} CustomStringConvertible {var description: String {return "name: \(name) singer: \(singer)"}}Copy the code

2.1.1 Traditional programming

  1. So let’s write a ViewModel
Struct MusicListViewModel {let data = [Music(name: "no strings ", singer:" easy "), Music(name: "easy ") "You used to be a teenager," singer: "S.H.E"), Music (name: "once upon a time I", the singer: "chen2 jie2 yi2"), Music (name: "Jupiter," singer: "hackberry),]}Copy the code
  1. ViewController code (viewcontroller.swift)
  • We then set up the delegate of the UITableView and have the view controller implement the UITableViewDataSource and UITableViewDelegate protocols, as well as the associated protocol methods.
  • I’m sure you’ve written this a million times, and there’s nothing to tell. So let’s see, this is 43 lines of code.
Import UIKit import RxSwift class ViewController: UIViewController {//tableView @ibOutlet weak var tableView: UITableView! Override func viewDidLoad() {super.viewdidLoad () // Set the proxy tableView.dataSource = self tableView.delegate = self } } extension ViewController: Func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) - > Int {return musicListViewModel. Data. The count} / / returns the corresponding cell func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "musicCell")! let music = musicListViewModel.data[indexPath.row] cell.textLabel? .text = music.name cell.detailTextLabel?.text = music.singer return cell } } extension ViewController: UITableViewDelegate {// Cell click func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {print(" Information about the selected song [\(musicListViewModel.data[indepath.row])] ")}}Copy the code
  • Let’s look at the programming of Rxswift

2.1.2 Rxswift programming

  1. right ViewModelDo some modification
    1. Here we turn the data property into an observable sequence object (Observable Squence), and the contents of the object are exactly the same as those contained in the array.
    2. I’ll talk more about observable sequence objects in a later article. Simply put, a “sequence” can subscribe to these values.Subscribe), somewhat similar to “Notice (NotificationCenter)”
Import RxSwift // struct MusicListViewModel {let data = Observable. Just ([Music(name: "no strings ", singer: "Eason Chan "), Music(Name:" You were a Teenager ", Singer: "S.H.E"), Music(name: "Formerly me ", Singer:" Kit Chan "), Music(Name: "In Jupiter ", Singer: "Hackberry "),])}Copy the code
  1. ViewController code (viewcontroller.swift)
    1. We no longer need to implement datasource and delegate protocols. I’m going to write some reactive code that binds the data to the UITableView.
    2. We’re only going to need 31 lines of code here, which is a quarter less code than we had before. And the code is a little cleaner.
    3. DisposeBag: Rx automatically interprets the resources bound to the view controller or its owner when it is about to be destroyed. It is implemented through a “subscription disposition mechanism” (similar to removeObserver of NotificationCenter). Rx.items (cellIdentifier:) : This is a wrapper around RX based on the cellForRowAt data source method. In the traditional way we also have a numberOfRowsInSection method, which is no longer needed when we use Rx (Rx already does that for us). Rx. modelSelected: This is a wrapper around RX based on the UITableView delegate callback method didSelectRowAt.

import UIKit import RxSwift import RxCocoa class ViewController: UIViewController {//tableView object @ibOutlet weak var tableView: UITableView! // Let musicListViewModel = musicListViewModel () // Responsible object destruction let disposeBag = disposeBag () override func ViewDidLoad () {super.viewdidLoad () // Bind the data source to the tableView musicListViewModel.data.bind (to: tableView.rx.items(cellIdentifier:"musicCell")) { _, music, cell in cell.textLabel? .text = music.name cell.detailTextLabel?.text = music.singer }.disposed(by: DisposeBag) / / tableView click response tableView. Rx. ModelSelected (Music. The self). The subscribe (onNext: Disposed (by: disposeBag)}} {music in print(" Disposed song [\(music)] ")}).Copy the code

2.2 Observable Describes and creates Observable sequences

  • Observable is the foundation of Rx, so we need to get a basic understanding of it.
  • Observable:

The Observable class, which is the basis of the Rx framework, is called an Observable sequence. What it does is generate a series of events asynchronously, that is, an Observable emits events (Element: T) irregularly over time. These events can also carry data, and their generics are used to specify the type of data carried by the Event. With Observable sequences, we also need an Observer to subscribe to them so that the subscriber can receive the events that an Observable emits from time to time.

  • Event
  • If you look at the RxSwift source code, you can find that the Event is defined as follows:
public enum Event<Element> {
    /// Next element is produced.
    case next(Element)
 
    /// Sequence terminated with an error.
    case error(Swift.Error)
 
    /// Sequence completed successfully.
    case completed
}
Copy the code
  • You can see that an Event is an enumeration, which means that an Observable emits three different types of events:
    • next:nextAn event is an event that can carry data, and it can be said to be the “most normal” event.
    • error:errorAn event represents an error, and it can carry specific error content once Observableissuederror event, thisObservableSo it’s going to terminate, and it’s not going to emit an event anymore.
    • completed:completedThe event saidObservableThe emitted event ends normally, just like error, once Observableissued completed event, this ObservableSo it’s going to terminate, and it’s not going to emit an event anymore.

2.2.1 Comparison between Observable and Sequence

  • 1) For better understanding, we can take each of themObservableImagine the Sequence in a Swift:
    • That is, aObservable(ObservableType) is equivalent to a sequenceSequence(SequenceType).
    • ObservableType.subscribe(_:)The method is essentially the same thing asSequenceType.generate()
  • 2) But there are many differences:
    • The Swift,SequenceTypeIt’s a synchronous cycle, andObservableIt’s asynchronous.
    • ObservableThe object automatically passes the Event as a parameter when it has any EventObservableType.subscribe(_:)Emit, without using the next method.

2.2.2 Creating an Observable sequence

  • There are several ways to create an Observable sequence
  1. Just () method

(1) The method is initialized by passing in a default value. (2) In the following example, the type of observable is explicitly marked as Observable, which specifies that the data type of the event emitted by the Observable must be Int.

let observable = Observable<Int>.just(5)
Copy the code
  1. Of () method

(1) The method can accept a variable number of arguments (all of the same type). (2) In the example below, I don’t explicitly declare the generic type of Observable, and Swift will automatically infer the type.

let observable = Observable.of("A", "B", "C")
Copy the code
  1. The from () method

(1) This method takes an array argument. (2) The elements in the data in the following example are treated as the data content of the Observable event. The result is the same as in the of() example above.

let observable = Observable.from(["A", "B", "C"])
Copy the code
  1. The empty() method creates an Observable sequence of empty content.
let observable = Observable<Int>.never()
Copy the code
  1. The never() method creates an Observable sequence that never emits an Event (and never terminates).
let observable = Observable<Int>.never()
Copy the code
  1. The error() method creates an Observable that does nothing but sends an error.
enum MyError: Error {
    case A
    case B
}
         
let observable = Observable<Int>.error(MyError.A)
Copy the code
  1. The range () method

(1) This method creates an Observable sequence that starts with all values in the range by specifying the start and end values. (2) In the following example, the two methods create the same Observable sequence.

Range (start: 1, count: 5) let Observable = Observable.of(1, 2, 3,4,5)Copy the code
  1. RepeatElement () this method creates an Observable sequence that emits events for the given element indefinitely (never terminating).
let observable = Observable.repeatElement(1)
Copy the code
  1. The generate () method

(1) This method creates an Observable that gives an action only when all the provided criteria are true. (2) In the following example, the two methods create the same Observable sequence.

// Use the generate() method let Observable = observable. Generate (initialState: 0, condition: {$0 <= 10}, iterate: {$0 + 2}) // Let Observable = Observable. Of (0, 2,4,6,8,10)Copy the code
  1. The create () method

(1) The method takes a block and processes each incoming subscription. (2) Here is a simple example. Subscription code has been added for demonstration purposes

// The block has a callback, observer, that subscribes to the Observable. // When a subscriber subscribes to the Observable, Let Observable = Observable<String>. Create {observer in // emits a.next event to the subscriber, OnNext ("hangge.com") // issued to the subscriber. Completed Event observer.oncompleted () // Since a subscription has a return value of type Disposable, Make sure to returen a Disposable return Disposables. Create ()} // Subscribe observable. Subscribe {print($0)}Copy the code
  1. Deferred () method

(1) This method is equivalent to creating an Observable factory, which executes deferred Observable creation by passing in a block where the actual sequence object is instantiated. (2) Here is a simple demo:

Var isOdd = true // Defer Observable initialization with deferred() method, pass block to initialize Observable and return. Let factory: Observable<Int> = Observable.deferred {// Make the block alternate between odd and even. IsOdd =! IsOdd // According to isOdd, Observable if isOdd {return Observable. Of (1, 3, 5,7)}else {return Observable. Of (2, 4, 6); Factory. Subscribe {event in print("\(isOdd)", Factory. Subscribe {event in print("\(isOdd)", event)}Copy the code

The results are as follows, and we can see that the two observables we subscribe to are different:

  1. The interval () method

(1) The Observable created by this method emits an index element every set period of time. And it’s going to keep going. (2) the following method causes it to be sent every 1 second and is sent from the MainScheduler.

let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable.subscribe { event in
    print(event)
}
Copy the code
  1. The timer () method
  • (1) There are two ways to use this method. One is to create an Observable sequence that generates a unique element after a set period of time.
/ / 5 seconds after making only one element 0 let observables = observables < Int >. The timer (5, the scheduler: MainScheduler.instance) observable.subscribe { event in print(event) }Copy the code
  • (2) The other is an Observable sequence that generates an element at intervals after a set period of time.
Timer (5, period: 1, scheduler: 1, scheduler: 1, scheduler: 1); MainScheduler.instance) observable.subscribe { event in print(event) }Copy the code

2.3 Observable subscription, Event listening, and subscription destruction

2.3.1 observables subscription

  • With an Observable, we also subscribe to it using the subscribe() method and receive its events.

2.3.1.1 The first subscription method

  • (1) We subscribe to an Observable using subscribe(). The block callback parameter of this method is the emitted event, which we print directly.
let observable = Observable.of("A", "B", "C")
         
observable.subscribe { event in
    print(event)
}
Copy the code

The result is as follows:

The default values set when initializing the Observable sequence are sent sequentially through the.next event. When the Observable completes sending the initial data, it automatically emits a.Completed event.

  • (2) If you want to obtain the data of this event, you can obtain it through event. Element.
let observable = Observable.of("A", "B", "C")
         
observable.subscribe { event in
    print(event.element)
}
Copy the code

The running results are as follows:

2.3.1.2 Second subscription method

  • (1) RxSwift also provides another subscribeMethod, which can categorize events:
    • Different types of events are handled through different block callbacks. (Where onDisposed indicates the callback after the subscription is disposed)
    • At the same time, the data carried by the event will be directly unpacked as parameters, which is convenient for us to use.
let observable = Observable.of("A", "B", "C")
         
observable.subscribe(onNext: { element in
    print(element)
}, onError: { error in
    print(error)
}, onCompleted: {
    print("completed")
}, onDisposed: {
    print("disposed")
})
Copy the code

The running results are as follows:

  • (2)subscribe()methodsonNext,onError,onCompleted 和 onDisposedThe four callback block arguments have default values, that is, they are optional. So we could just do itonNextRegardless of the other cases.
let observable = Observable.of("A", "B", "C")
         
observable.subscribe(onNext: { element in
    print(element)
})
Copy the code

The command output is as follows: A B C

2.3.2 Event Listening

  • Introduce’s elite doOn

(1) We can use the doOn method to listen for the life cycle of events, which will be called before each event is sent. (2) Like SUBSCRIBE, it can handle different types of events through different block callbacks. For example, the do(onNext:) method is called before subscribe(onNext:) and the do(onCompleted:) method is called before subscribe(onCompleted:).

  • Use the sample
let observable = Observable.of("A", "B", "C") observable .do(onNext: {element in print("Intercepted Next: ", element)}, onError: {error in print("Intercepted error: ", error)}, onCompleted: {print("Intercepted Completed")}, onDispose: { print("Intercepted Disposed") }) .subscribe(onNext: { element in print(element) }, onError: { error in print(error) }, onCompleted: { print("completed") }, onDisposed: { print("disposed") })Copy the code

2.3.3 Subscription destruction

2.3.3.1 Observable Creation to Termination Process

  • (1) One ObservableInstead of being activated immediately after a sequence is created to emit events, it is activated only when it has been subscribed by someone.
  • (2) ObservableOnce the sequence is activated, wait until it’s emitted.erroror .completed eventAfter that, it was ended.

2.3.3.2 the dispose () method

  • (1) Using this method we can manually cancel a subscription behavior.
  • (2) If we feel that the subscription has ended and is no longer needed, we can call itdispose()Method to destroy the subscription to prevent a memory leak.
  • (3) When a subscription action is disposeAnd then after that observableIf it is sent againeventThis has beendisposeYou can’t receive messages from your subscription. Here is a simple usage example.
let observable = Observable.of("A", "B", Subscribe {event in print(event)} // Call the dispose() method of the subscription subscription.dispose()Copy the code

2.3.3.13 DisposeBag

  • (1) In addition to dispose() method, we more often use an object called DisposeBag to manage the destruction of multiple subscriptions:
  1. We can think of a DisposeBag object as a garbage bag into which we can put all of our used subscriptions.
  2. The DisposeBag then calls its Dispose () method on all subscriptions as it approaches dealloc.
  • (2) Below is a simple usage example.
Let disposeBag = disposeBag () Observable1 = observable. of("A", "B", "C") observable1. Subscribe {event in print(event)}. DisposeBag) // the second Observable, Observable2 = Observable.of(1, 2, 3) observable2.subscribe {event in print(event)}. Disposed (by: disposeBag)Copy the code

2.4 AnyObserver and Binder

2.4.1 Observer (Observer)

  • The role of an Observer, “Observer,” is to listen for an event and then respond to that event. Or anything that responds to an event is an observer. Such as:
    • When we click the button, a prompt box pops up. The Observer is an Observer
    • When we request a remote JSON data, we print it out. So this “print JSON data” is the Observer

2.4.2 Creating an Observer

2.4.2.1 Create observer directly in subscribe and bind methods

  1. Created in the SUBSCRIBE method

(1) The most direct way to create an observer is to describe how to respond to an event after the Subscribe method of an Observable. (2) In the following example, the observer is constructed from the following closures: onNext, onError, onCompleted.

let observable = Observable.of("A", "B", "C")
          
observable.subscribe(onNext: { element in
    print(element)
}, onError: { error in
    print(error)
}, onCompleted: {
    print("completed")
})
Copy the code

Running results:

  1. Create an Observable that periodically generates index numbers and displays them on the label tag:
Scheduler (1, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler) Mainscheduler. instance) observable. map {" Current index: Prompt ($0)"}. Bind {[weak self](text) in self?.label.text = text}. Disposed (by: disposeBag)Copy the code

2.4.2.2 Creating an Observer using AnyObserver

  • AnyObserver can be used to describe any kind of observer.
  • Used in conjunction with the SUBSCRIBE method
// Let observer: AnyObserver<String> = AnyObserver {(event) in switch event {case.next (let data): print(data) case .error(let error): print(error) case .completed: print("completed") } } let observable = Observable.of("A", "B", "C") observable.subscribe(observer)Copy the code
  • Use with bindTo method
// Observer let observer: AnyObserver<String> = AnyObserver {[weak self] (event) in switch event {case.next (let text): // Display the index on the label self? .label.text = text default: Scheduler (1, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler) Mainscheduler.instance) Observable. map {" Current index: \($0)"}. Bind (to: observer). Disposed (by: disposeBag)}Copy the code

2.4.2.3 Using Binder to create observers

(1) Binder is more focused on specific scenarios than AnyObserver. Binder does not handle error events and ensures that bindings are executed on a given Scheduler (MainScheduler by default). (2) fatalError will be executed in debug and error messages printed in publish.

  • Instance 2.4.2.3
// let observer: Binder<String> = Binder(label) { (view, View. text = text} //Observable (emits an index every 1 second) let Observable = Observable<Int>. Interval (1, scheduler: mainScheduler.instance) Observable. map {" Current index: \($0)"}. observer) .disposed(by: (1, scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler: scheduler; MainScheduler.instance) observable .map { $0 % 2 == 0 } .bind(to: button.rx.isEnabled) .disposed(by: disposeBag)Copy the code

2.5 Customizing Binding Attributes

  • Sometimes we want UI controls to have some observers by default when they are created, rather than having to create separate observers for them each time. For example, we want all uilabels to have a fontSize binding property that automatically changes the fontSize of the label based on the event value.

  • By extending the UI class here we’ve extended UILabel to add a fontSize binding property.

import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { @IBOutlet weak var label: UILabel! Func Observable () {// Let Observable = disposeBag () override func Observable () {// Let Observable = disposeBag () override func Observable () {// Let Observable = disposeBag () override func Observable () {// Let Observable = disposeBag () override func Observable () Observable<Int>. Interval (0.5, scheduler: mainScheduler.instance) Observable. map {CGFloat($0)}. Disposed (by: disposeBag)}} Extension UILabel {public var fontSize: Binder<CGFloat> { return Binder(self) { label, fontSize in label.font = UIFont.systemFont(ofSize: fontSize) } } }Copy the code
  • Since you use RxSwift, the more formal way to write this is to extend Reactive. Again, we’re adding a fontSize binding property to UILabel.
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { @IBOutlet weak var label: UILabel! Func Observable () {// Let Observable = disposeBag () override func Observable () {// Let Observable = disposeBag () override func Observable () {// Let Observable = disposeBag () override func Observable () {// Let Observable = disposeBag () override func Observable () Observable<Int>. Interval (0.5, scheduler: mainScheduler.instance) Observable. map {CGFloat($0)}. Prompt (by: disposeBag)}} extension Reactive where Base: UILabel { public var fontSize: Binder<CGFloat> { return Binder(self.base) { label, fontSize in label.font = UIFont.systemFont(ofSize: fontSize) } } }Copy the code
  • RxSwift binding properties (UI Observer)

In fact, RxSwift already provides us with many common bindable properties. UILabel, for example, has two binding attributes, text and attributedText.

extension Reactive where Base: UILabel { /// Bindable sink for `text` property. public var text: Binder<String? > { return Binder(self.base) { label, text in label.text = text } } /// Bindable sink for `attributedText` property. public var attributedText: Binder<NSAttributedString? > { return Binder(self.base) { label, text in label.attributedText = text } } }Copy the code

In the example above, we don’t need to customize the UI observer. We can just use the binding property provided by RxSwift.

Scheduler (1, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler, scheduler) Mainscheduler.instance) Observable. map {" Current index: \($0)"}. Bind (to: label.rx.text) // When the sent index is displayed on the label. disposeBag)Copy the code

2.6 the Subjects, the Variables

When we create an Observable, we prepare all the data that will be sent out in advance, and wait until someone subscribes to it to send the data out via events. But sometimes we want an Observable to dynamically “get” or “produce” new data at runtime and send it out via events. For example, subscribe to the input content of an input box. When a user enters a word, the Observable associated with the input box issues an Event with the input content to notify all subscribers. This can be done using Subjects, which will be described below.

2.6.1 the Subjects

2.6.1.1 introduction of the Subjects

  • (1) Subjects are both subscribers and Observables:

It is a subscriber because it can dynamically receive new values. It is also an Observable, because when Subjects has a new value, it sends the new value to all its subscribers through events.

  • (2) There are four types of Subjects:PublishSubject,BehaviorSubject,ReplaySubject,Variable. They have their own characteristics, but also have something in common:
  1. First of all, they all areObservableTheir subscribers can receive the new ones they send outEvent.
  2. untilSubjecta.completeor.errorEventLater, theSubjectIt ends, and it doesn’t go out again.nextEvents.
  3. For those in theSubjectSubscribers who subscribe to him after the end will also receive itsubjectSent out.complete.error theeventAnd tell the new subscriber that it’s over.
  4. The biggest difference between them is whether a new subscriber can receive it when they first subscribeSubjectOld ones that have been issued before EventAnd how many, if any.
  • (3) Several methods commonly used by Subject:
  1. onNext(:): it is on (. Next (?) Is a convenient way to write. This method is equivalent to the subject receiving a.next event.
  2. onError(:): it is on (. Error (?) Is a convenient way to write. This method is equivalent to the subject receiving an.error event.
  3. onCompleted(): is a convenient form of on(.completed). This method is equivalent to the subject receiving a.Completed event.

2.6.1.2 PublishSubject

  • (1) Basic introduction

The PublishSubject is the most common Subject that can be created without an initial value. PublishSubject subscribers can receive new events issued by the Subject after the subscription from the time they started the subscription, but not events they issued before the subscription.

  • (2) Sequence diagram

    The picture is as follows: The top one isPublishSubject.

    The following two represent two new subscriptions, which are subscribed at different points in time, as you can seePublishSubjectSubscribers will only receive their subscriptionsEvent.

  • Instance 2.6.1.2:
Let disposeBag = disposeBag () // Create a PublishSubject let subject = PublishSubject<String>() OnNext ("111") // First subscription subject subject.subscribe(onNext: Prompt ({string in print(" prompt subscription: ", string)}, onCompleted:{print(" prompt subscription: ")}). Disposed (by: DisposeBag) // If there is currently one subscription, this information will be printed to console subjection.onnext ("222") // Second subscription subject subjection.subscribe (onNext: Prompt ({string in print(" Second subscription: ", string)}, onCompleted:{print(" second subscription: onCompleted")}). Disposed (by: DisposeBag) // There are currently 2 subscriptions, this information will be output to the console subjection.onNext ("333") // Let subject finish subjection.oncompleted () // the.next event will be emitted when subject completes. OnNext ("444") // After the subject has completed all its subscriptions (including those that have finished), it receives the. Subscribe (onNext: Disposed (by: disposeBag) {string in print(" third subscription: ", string)}, onCompleted:{print(" third subscription: onCompleted")}). Disposed (by: disposeBag)Copy the code

Running results:

2.6.1.3 BehaviorSubject

  • (1) Basic introduction

The BehaviorSubject needs to be created with a default initial value. When a subscriber subscribes to it, the subscriber immediately receives an event emitted on BehaviorSubjects. Then, just like normal, it also receives a new event emitted by the BehaviorSubject.

  • (2) Sequence diagram

Figure 1 shows a BehaviorSubject at the top. The following two subscriptions represent two new subscriptions at different times. You can see that the subscriber of BehaviorSubject starts out with an Event that BehaviorSubjects sent earlier.

  • Instance 2.6.1.3
Let disposeBag = disposeBag () // Create a BehaviorSubject. Prompt {subscribe {event in print(" first subscription: ", event)}. Prompt (by: OnNext ("222") // Send error event subject.onError(NSError(domain: "local", code: 0, userInfo: Prompt {subscribe {event in print(" Second subscription: ", event)}. Disposed (by: disposeBag)Copy the code

Running results:

2.6.1.4 ReplaySubject

  • (1) Basic introduction
  1. ReplaySubjectYou need to set one at creation timebufferSize, indicating that it has senteventNumber of caches.
  2. For example, aReplaySubjectthe bufferSizeSet to 2 and it sends out 3 .next event, then it will divide the last two (the nearest two)eventCache it. Now if I have onesubscriberSubscribe to this ReplaySubjectSo thissubscriberIt will immediately receive the first two cached .next event.
  3. If asubscriberSubscription has ended ReplaySubjectExcept that it will receive a cache .nextevent Also, you will receive the termination.erroror .completeevent.
  • (2) Sequence diagram

    The picture is as follows: The top one isReplaySubject (bufferSizeSet it to 2).

    The following two represent two new subscriptions at different points in time. You can findReplaySubjectSubscribers will receive it right from the start ReplaySubjectThe two we sent out earlierEvent(if any).

  • Instance 2.6.1.4:
Let disposeBag = disposeBag () // Create a ReplaySubject with bufferSize 2. Let subject = ReplaySubject<String>. OnNext ("222") subject.onnext ("222") subject.onnext ("333") // first subscribed subject subject.subscribe { Object in print(" prompt subscription: ", event)}. Disposed (by: DisposeBag) // Send 1 next event subject.onnext ("444") // subscribe for the 2nd time. ", event) }.disposed(by: Unsubscribe {event in print(" unsubscribe for the third time: ", event) }.disposed(by: disposeBag)Copy the code

Running results:

2.6.2 Variables

  • Note: Since Variable will be deprecated in future releases, it is recommended that you use BehaviorRelay as described below instead of Varible

2.6.2.1 Variable

  • (1) Basic introduction
  1. VariableIn fact, yes. BehaviorSubjectSo it must also be created with a default initial value.
  2. Variablewith BehaviorSubjectTo send a message to its subscriberseventAnd the ones that are created after that event.
  3. The difference is,VariableIt also saves the currently emitted value as its own state. It will also be sent automatically when destroyed .complete eventIt is not necessary and cannot be given manually Variablessendcompletedor errorEvents to end it.
  4. In a nutshell VariableThere is a valueProperty, let’s change thisvalueThe value of the property is equivalent to the call generalSubjectstheonNext()Method, and this latest one onNext()The value of is saved invalueProperty, until we modify it again.
  5. Variables Itself has no subscribe()Method, but allSubjectsThere is aasObservable()Methods. We can use this method to return this VariableObservableType, get thisObservable Type we can subscribe to it.
  • Instance 2.6.2.1
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let disposeBag = DisposeBag() // Create a Variable let Variable = Variable("111") // change value Variable. Value = "222" // first subscription Mod.asobservable (). Subscribe {print(" first subscription: ", $0)}. Prompt (by: Variable. value = "333" // subscribe variable.asobservable (). Subscribe {print(" subscribe ") ", $0) }.disposed(by: Value = "444"}} Note: Since the variable object is initialized in the viewDidLoad() method, its lifetime is limited to that method. When this method completes, the Variable object is destroyed, and it automatically issues the.completed event to all its subscribersCopy the code

Running results:

2.6.2.2 BehaviorRelay

  • 1) Basic introduction
  1. BehaviorRelayAs aVariableA replacement has emerged. It’s also true in natureBehaviorSubjectSo it must also be created with a default initial value.
  2. BehaviorRelaywithBehaviorSubjectTo send the last one to its subscriberseventAnd the ones that are created after thatevent.
  3. withBehaviorSubjectThe difference is that manual feeding is not required and cannot be doneBehaviorReplysendcompletedor errorEvents to end it (BehaviorRelayWill not be automatically sent when destroyed .completeevent).
  4. BehaviorRelayThere is avalueProperty by which we can get the latest value. And what goes through itaccept()Method can modify values.

(2) The sample BehaviorRelay could be converted to BehaviorRelay. The code is as follows:

import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let disposeBag = DisposeBag() // Create a BehaviorRelay let subject = BehaviorRelay<String>(value: Subscribe {print(" first subscription: ", $0)}. Disposed (by: Accept ("333") // subscribe for 2 times. Subscribe {subscribe for 2 times: ", $0)}. Disposed (by: disposeBag) // Modify value subject.accept("444")}}Copy the code

Running results:

  • (3) If you want to merge the new value to the original value, you can passaccept()The methods andvalueProperty to implement. (This is often used with pull and load functions on tables,BehaviorRelayTo save all loaded data)
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let disposeBag = DisposeBag() The BehaviorRelay let subject = BehaviorRelay<[String]>(value: ["1"]) // Modify value subject.accept(subject.value + ["2", "3"]) // subscribe subject.asobservable (). Subscribe {print(" 1") ", $0) }.disposed(by: Accept (subject.value + ["4", "5"]) // Subscribe subjent.asObservable (). Subscribe {print(" Subscribe 2: ", $0)}. Prompt (by: Accept (subject.value + ["6", "7"])}}Copy the code

Running results:

2.7 Transformation operators: Buffer, map, flatMap, scan, etc

  • Transform operations refer to transformations of the original Observable sequence, similar to the conversions of CollectionType in Swift.

2.7.1 buffer

  • (1) Basic introduction

The buffer method is a buffer combination. The first parameter is the buffer time, the second parameter is the number of buffers, and the third parameter is the thread. This method simply caches new elements emitted by an Observable, and when the number of elements reaches a certain number or a certain amount of time passes, it sends the collection of elements out.

  • Instance 2.7.1
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { let disposeBag = DisposeBag() override func viewDidLoad() { let subject = PublishSubject<String>() // Each cache of 3 elements is combined and emitted together. Buffer (timeSpan: 1, count: 3, scheduler: 1) MainScheduler.instance) .subscribe(onNext: { print($0) }) .disposed(by: disposeBag) subject.onNext("a") subject.onNext("b") subject.onNext("c") subject.onNext("1") subject.onNext("2") subject.onNext("3") } }Copy the code

Running results:

2.7.2 window

  • (1) Basic introduction

The window operator is very similar to buffer. Buffers periodically send cached elements, whereas Windows periodically send elements as observables. At the same time, the buffer will not issue the element sequence until the element is collected. Windows emits sequences of elements in real time.

  • Instance 2.7.2
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController { let disposeBag = DisposeBag() override func viewDidLoad() { let subject = PublishSubject<String>() // Every three elements is emitted as a child Observable. subject .window(timeSpan: 1, count: 3, scheduler: MainScheduler.instance) .subscribe(onNext: { [weak self] in print("subscribe: \($0)") $0.asObservable() .subscribe(onNext: { print($0) }) .disposed(by: self! .disposeBag) }) .disposed(by: disposeBag) subject.onNext("a") subject.onNext("b") subject.onNext("c") subject.onNext("1") subject.onNext("2") subject.onNext("3") } }Copy the code

Running results:

2.7.3 map

  • This operator converts an Observable into a new Observable by passing in a function closure.

  • Instance 2.7.3
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3)
    .map { $0 * 10}
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Result: 10, 20, 30

2.7.4 flatMap

  • (1) Basic introduction
  1. mapIt is easy to “raise dimension” when doing transformations. That is, after the transformation, you go from a sequence to a sequence of sequences.
  2. whileflatMapThe operator will apply to the sourceObservableApply a conversion method to each element of theObservables. And then take thoseObservablesThe element is merged before being sent out. That is, it “flatten” (dimensionality reduction) into oneObservableSequence.
  3. This operator is very useful. Such as whenObservableThe element Bunsen has the othersObservableWhen, we can put all the childrenObservablesThe element is sent.

  • Instance 2.7.4
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .flatMap { $0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
Copy the code

Running results:

2.7.5 flatMapLatest

  • The only difference between flatMapLatest and flatMap is that flatMapLatest only receives the latest value event.

  • Example 2.7.5: Here we change the flatMap in the previous example to flatMapLatest
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .flatMapLatest { $0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
Copy the code

Running results:

2.7.6 flatMapFirst

  • (1) Basic introduction
  1. FlatMapFirst is the opposite of flatMapLatest: flatMapFirst only receives the initial value event.
  2. This operator prevents repeated requests: clicking a button to send a request, for example, should not continue until the request is complete. The flatMapFirst operator should be used.

  • Example 2.7.6: Here we change flatMapLatest from the previous example to flatMapFirst.
let disposeBag = DisposeBag()
 
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
 
let variable = Variable(subject1)
 
variable.asObservable()
    .flatMapFirst { $0 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")
Copy the code

Running results:

2.7.7 concatMap

  • (1) Basic introduction

The only difference between concatMap and flatMap is that a subsequent Observable can emit elements only after the current one has been sent. Or wait for the previous Observable to generate and complete the event before subscribing to the next Observable.

  • Instance 2.7.7
let disposeBag = DisposeBag() let subject1 = BehaviorSubject(value: "A") let subject2 = BehaviorSubject(value: "1") let variable = Variable(subject1) variable.asObservable() .concatMap { $0 } .subscribe(onNext: { print($0) }) .disposed(by: disposeBag) subject1.onNext("B") variable.value = subject2 subject2.onNext("2") subject1.onNext("C") Subject1.oncompleted () // The next sequence will be received only after the previous one has finishedCopy the code

Running results:

2.7.8 scan

  • (1) Basic introduction

Scan is to give an initial number, and then continuously take the previous result and the latest value for processing operation.

  • Instance 2.7.8
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4, 5)
    .scan(0) { acum, elem in
        acum + elem
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

The results

2.7.9 groupBy

  • (1) Basic introduction

The groupBy operator breaks up the source Observable into sub-Observables and sends them out. That is, the operator groups elements by a key and sends the grouped element sequence as an Observable.

  • Instance 2.7.9
Observable<Int>. Of (0, 1, 2, 3, 4, 5). { (element) -> String in return element % 2 == 0 ? }).subscribe {(event) in switch event {case.next (let group): Frame.asobservable ().subscribe({(event) in print("key: \(group. Key) event: \(event)")}). disposeBag) default: print("") } } .disposed(by: disposeBag)Copy the code

Running results:

2.8 Filter operators: filter, take, skip, etc

  • Filtering refers to sending specific data from a source Observable.

2.8.1 filter

  • (1) Basic introduction

This operator is used to filter out certain events that do not meet the requirements.

  • Instance 2.8.1
let disposeBag = DisposeBag()
 
Observable.of(2, 30, 22, 5, 60, 3, 40 ,9)
    .filter {
        $0 > 10
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

2.8.2 distinctUntilChanged

  • This operator is used to filter out continuously repeated events.

  • Instance 2.8.2
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 1, 1, 4)
    .distinctUntilChanged()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running results:

2.8.3 single

  • (1) Basic introduction

Restrict sending of only one event, or the first event that satisfies the condition. An error event is raised if there are multiple events or no events. If there is only one event, no error event is raised.

  • Instance 2.8.3
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .single{ $0 == 2 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
Observable.of("A", "B", "C", "D")
    .single()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running results:

2.8.4 elementAt

  • This method implementation only handles events at a specified location.

  • Instance 2.8.4
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .elementAt(2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running result: 3

2.8.5 ignoreElements

  • (1) Basic introduction

This operator can ignore all elements and only issue an error or completed event. We can use the ignoreElements operator if we don’t care about any of the Observable’s elements and just want to know when the Observable terminates.

  • Instance 2.8.5
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .ignoreElements()
    .subscribe{
        print($0)
    }
    .disposed(by: disposeBag)
Copy the code

Result: completed

2.8.6 take

  • This implementation sends only the first n events in the Observable sequence, and.completed is automatically completed when the number is satisfied.

  • Instance 2.8.6
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .take(2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running results: 1 2

2.8.7 takeLast

  • This implementation sends only the last n events in the Observable sequence.

  • Instance 2.8.7
let disposeBag = DisposeBag()
 
Observable.of(1, 2, 3, 4)
    .takeLast(1)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running result: 4

2.8.8 skip

  • This method skips the first n events emitted by the source Observable sequence.

Running results: 3 4

2.8.9 Sample

  1. In addition to subscribes to the source Observable, Sample can also monitor another Observable, namely, notifier.
  2. Each time a Notifier event is received, the latest event is fetched from the source sequence and sent. If there is no event in the source sequence between notifier events, no value is sent.

  • Instance 2.8.9
let disposeBag = DisposeBag() let source = PublishSubject<Int>() let notifier = PublishSubject<String>() source .sample(notifier) .subscribe(onNext: { print($0) }) .disposed(by: OnNext ("A") source.onnext (2) notifier. OnNext ("B") OnNext ("D") source.onNext(5) // Make the source sequence receive the receive message notifier.onCompleted()Copy the code

Running results:

1, 2, 4, 5

2.8.10 debounce

  • (1) Basic introduction
  1. The debounce operator, which can be used to filter out high-frequency elements, emits only the element after which no new element has been created for a period of time.
  2. In other words, the element in the queue will be filtered out if the interval between the element and the next element is less than the specified interval.
  3. Debounce is often used when a user types, instead of sending an event for each letter typed, it waits for the last event to be taken.

  • Instance 2.8.10:
import UIKit import RxSwift import RxCocoa class ViewController: UIViewController {let disposeBag = disposeBag () override func viewDidLoad() {let times = [[ "Value" : 1, "time" : 0.1], [" value ": 2," time ": 1.1], [3," value ":" the time ": 1.2], [" value" : 4, "time" : 1.2], [5, "value" : "the time" : 1.4], [6, "value" : "the time" : From (times). FlatMap {item in return Observable. Of (Int(item["value"]!) ) .delaySubscription(Double(item["time"]!) , scheduler: mainScheduler.instance)}. Debounce (0.5, scheduler: Mainscheduler.instance) // Emit only elements that are more than 0.5 seconds removed from the next frame.subscribe (onNext: {print($0)}).subscribe(by: disposeBag)}}Copy the code

Running results: 1 5 6

2.9 Conditional and Boolean operators: AMb, takeWhile, skipWhile, etc

  • Conditional and Boolean operations emit or transform Observables based on conditions, or perform Boolean operations on them.

2.9.1 amb

  • When passed multiple Observables ambOperator, which takes the first emitted element or produces the event ObservableAnd emits only its elements. And ignore the restObservables.

  • Instance 2.9.1
let disposeBag = DisposeBag()
 
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
let subject3 = PublishSubject<Int>()
 
subject1
    .amb(subject2)
    .amb(subject3)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject2.onNext(1)
subject1.onNext(20)
subject2.onNext(2)
subject1.onNext(40)
subject3.onNext(0)
subject2.onNext(3)
subject1.onNext(60)
subject3.onNext(0)
subject3.onNext(0)
Copy the code

Running results: 1, 2, 3

2.9.2 takeWhile

  • The method in turn determines whether each value of the Observable sequence satisfies a given condition. It completes automatically when the first value that does not meet the condition appears.

  • Instance 2.9.2
let disposeBag = DisposeBag()
 
Observable.of(2, 3, 4, 5, 6)
    .takeWhile { $0 < 4 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running results: 2 3

2.9.3 takeUntil

  • Basic introduction
  1. In addition to subscriptionsObservableOutside,takeUntilMethod we can also monitor another oneObservable, i.e.,notifier.
  2. ifnotifierA value orcompleteNotice, then sourceObservableAutomatically completes, and stops sending events.

  • Instance 2.9.3
let disposeBag = DisposeBag() let source = PublishSubject<String>() let notifier = PublishSubject<String>() source .takeUntil(notifier) .subscribe(onNext: { print($0) }) .disposed(by: OnNext ("b") source.onNext("c") source.onnext ("d") // Stop receiving messages notifier. OnNext ("z") source.onNext("e") source.onNext("f") source.onNext("g")Copy the code

A, B, C, d

2.9.4 skipWhile

  • Basic introduction
  1. This method is used to skip all previous events that meet the criteria.
  2. Once an event that does not meet the criteria is encountered, it will not be skipped afterwards.

  • Instance 2.9.4
let disposeBag = DisposeBag()
 
Observable.of(2, 3, 4, 5, 6)
    .skipWhile { $0 < 4 }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
    }
}
Copy the code

Running results: 4 5 6

2.9.5 skipUntil

  • Basic introduction
  1. Ditto below takeUntilThe same,skipUntil In addition to subscriptionsObservableOutside, skipUntilMethod we can also monitor another one Observable, i.e., notifier
  2. with takeUntilOn the contrary. The source ObservableSequence events are skipped by default until notifierA value or completeNotice.

  • Instance 2.9.5
let disposeBag = DisposeBag() let source = PublishSubject<Int>() let notifier = PublishSubject<Int>() source .skipUntil(notifier) .subscribe(onNext: { print($0) }) .disposed(by: OnNext (1) source.onNext(2) source.onNext(3) source.onNext(4) source.onNext(5) // Start receiving messages Notifier. OnNext (0) source.onNext(6) source.onNext(7) source.onNext(8) notifier. OnNext (0) source.onnext (9)Copy the code

Running result: 6 7 8 9

2.10 Combine operators such as startWith, Merge, and zip

2.10.1 startWith

  • Basic introduction:

This method inserts event elements before the Observable sequence starts. These pre-inserted event messages are emitted before the event message is emitted

  • Illustration:

  • Instance 2.10.1
let disposeBag = DisposeBag()
         
Observable.of("2", "3")
    .startWith("1")
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running results: 1, 2, 3

  • Example 2.10.1.1: Multiple data can be inserted
let disposeBag = DisposeBag()
 
Observable.of("2", "3")
    .startWith("a")
    .startWith("b")
    .startWith("c")
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
Copy the code

Running results: C b A 2 3

2.10.2 merge

  • Basic introduction:

This method merges multiple (two or more) Observable sequences into one Observable.

  • Illustration:

  • Instance 2.10.1
let disposeBag = DisposeBag()
         
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
 
Observable.of(subject1, subject2)
    .merge()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext(20)
subject1.onNext(40)
subject1.onNext(60)
subject2.onNext(1)
subject1.onNext(80)
subject1.onNext(100)
subject2.onNext(1)
Copy the code

Running results: 20 40 60 1 80 100 1

2.10.3 zip

  • Basic introduction:

This method compresses multiple (two or more) Observables into a single Observable. And it waits until each Observable event corresponds to one another before merging.

  • Illustration: \

  • Instance 2.10.1
let disposeBag = DisposeBag()
         
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()
 
Observable.zip(subject1, subject2) {
    "\($0)\($1)"
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)
Copy the code

Running results:

1A

2B

3C

4D

  • Zip is often used to consolidate network requests:

For example, if we want to send two requests at the same time, only after both requests are successful, we can combine the results of the two requests and continue processing. This can be done with zip.

// Let userRequest: Observable<User> = api.getUser ("me") // Let friendsRequest: Observable<User> = API. Observable<Friends> = api.getFriends ("me") {// Merge two requests in Observable. Zip (userRequest, friendsRequest) {user, // Combine two signals into one signal, Return (user, friends)}. ObserveOn (mainScheduler.instance) // This is added because the request is in the background thread, and the following bindings are in the foreground thread. .subscribe(onNext: {(user, friends) in // To bind data to the interface //....... }) .disposed(by: disposeBag)Copy the code

2.10.4 combineLatest

  • Basic introduction:
  1. This method also merges multiple (two or more) Observable sequence elements.
  2. Unlike ZIP, however, it merges the latest event element of each Observable sequence whenever a new event is emitted.
  • Illustration:

  • Instance 2.10.1
let disposeBag = DisposeBag()
         
let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()
 
Observable.combineLatest(subject1, subject2) {
    "\($0)\($1)"
    }
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)
Copy the code

Running results:

2.10.5 withLatestFrom

  • Basic introduction:

This method merges two Observable sequences into one. Each time the self queue emits an element, the latest value is fetched from the second sequence.

  • Illustration:
  • Instance 2.10.1
let disposeBag = DisposeBag()
 
let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()
 
subject1.withLatestFrom(subject2)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
 
subject1.onNext("A")
subject2.onNext("1")
subject1.onNext("B")
subject1.onNext("C")
subject2.onNext("2")
subject1.onNext("D")
Copy the code

Running results:

1

1

2

2.10.6 switchLatest

  • Basic introduction:

SwitchLatest is a bit like the switch method in other languages to transform the stream of events. For example, I can change the source of the event by changing the value of the variable in subject1. Becomes listen on Subject2.

  • Illustration:

  • Instance 2.10.1
let disposeBag = DisposeBag() let subject1 = BehaviorSubject(value: "A") let subject2 = BehaviorSubject(value: "1") let variable = Variable(subject1) variable.asObservable() .switchLatest() .subscribe(onNext: { print($0) }) .disposed(by: OnNext ("B") Subject1.onNext ("C") // Change the event source variable.value = Subject2 Subject1.onNext ("D") Value = Subject1 Subject2.onNext ("3") Subject1.onNext ("E")Copy the code

Running results:

Since the | address

Swift Books download:Download address