Create observables

// // ObservableTestvc. swift // BasicSwiftDemo // // Created by Pro on 2020/11/11. // Copyright © 2020 com.liufeng.mysterFeng. All rights reserved. // import UIKit enum MyError: Error { case A case B } let disposeBag = DisposeBag() class ObservableTestVC: UIViewController {override func viewDidLoad() {super.viewdidLoad (); // We can create an Observable by passing in default values to initialize lets observable1 = Observable<Int>.just(5) observable1.subscribe { print($0) }.disposed(by: Observable2 = Observable.of("A", "B", "C") observable2. Subscribe {print($0)}. Observable3 = Observable.from(["A", "B", "C"]) observable3. Subscribe {print($0)}. Observable4 = Observable4 <Int>. Empty () Observable4. Subscribe {print($0)}. Observable5 = Observable5 <Int>. Never () observable5. Subscribe {print($0)}. Observable6 = Observable<Int>. Error (myerror. A) Observable6. Subscribe {print($0) observable6 = Observable<Int>. Observable7 = Observable.range(start: 1, count: observable1) 5) observable7.subscribe{ print($0) }.disposed(by: Observable8 = observable. repeatElement(1) Observable8. Subscribe {print($0) Nextobservable9 = Observable.generate(initialState: observableState) {// If all conditions are satisfied prompt initial value 0 must be less than or equal to 10 + 2 per time 0, condition: { $0 <= 10 }, iterate: { $0 + 2 } ) observable9.subscribe{ print($0) }.disposed(by: Observable10 = Observable<String>. Create {observer in); // This block has a callback argument observer which is the subscriber of the Observable OnNext (" Observer.oncompleted () return Disposables. Create ()} print($0) }.disposed(by: 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)", event)}. Disposed (by: Factory. subscribe {event in print("\(isOdd)", event)}. Disposed (by: Observable12 = Observable<Int>. Interval (1, scheduler: observable12 = Observable<Int>. MainScheduler.instance) observable12.subscribe { event in print(event) }.disposed(by: Observable13 = Observable<Int>. Timer (5, scheduler:); MainScheduler.instance) observable13.subscribe { event in print(event) }.disposed(by: Observable14 = Observable<Int>. Timer (5, period: 1, scheduler: 1) MainScheduler.instance) observable14.subscribe { event in print(event) }.disposed(by: disposeBag) _ = Observable<Int>.timer(RxTimeInterval.milliseconds(500), scheduler: MainScheduler.instance) } }Copy the code

Subscribe to observer

RxSwift also provides another subscribe method, which classifies events

  • Different types of events are handled through different block callbacks
  • At the same time, the data carried by the event will be directly unpacked as parameters, which is convenient for us to use.
  • So we could just do onNext and leave the rest alone
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

3. Monitor event doOn

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

4. Observers

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.

  • Observers are built from closures such as onNext, onError, and onCompleted
  • Created in the bind method
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
  • AnyObserver creates an observer
// 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
  • Create an observer with Binder

Binder has the following two characteristics:

1. Error events are not handled

2. Ensure that bindings are executed on the given Scheduler (default MainScheduler)

// 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: disposeBag) }Copy the code

Application of Binder in RxCocoa

extension Reactive where Base: UIControl {
     
    /// Bindable sink for `enabled` property.
    public var isEnabled: Binder<Bool> {
        return Binder(self.base) { control, value in
            control.isEnabled = value
        }
    }
}

let observable = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
observable
    .map { $0 % 2 == 0 }
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)
Copy the code

5. Custom binding properties

1. Customize UI controls

extension UILabel {
    public var fontSize: Binder<CGFloat> {
        return Binder(self) { label, fontSize in
            label.font = UIFont.systemFont(ofSize: fontSize)
        }
    }
}
Copy the code

2. Extend the Reactive class

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 already provides you with a number of common bindable properties to read for yourself

Vi. Introduction of Subjects

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

Subjects are both a subscriber and an Observable

  • 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

Several methods commonly used by Subject

OnNext (:) : is a simple way of writing on(.next(:)). This method is equivalent to the subject receiving a.next event.

OnError (:) : is a shorthand for on(.error(:)). This method is equivalent to the subject receiving an.error event. OnCompleted () : is an easy way to write on(.completed). This method is equivalent to the subject receiving a.Completed event

There are four kinds of Subjects

  • PublishSubject
  • BehaviorSubject
  • ReplaySubject
  • Variable

Seven, transformation operation

  • buffer

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.

  • window

The window operator is very similar to buffer. Buffers periodically send cached elements, whereas Windows periodically send elements as observables.

  • map

This operator converts the original Observable into a new Observable by passing in a function closure.

  • flatMap

Map is prone to “raise dimensions” during transformation. That is, after the transformation, you go from a sequence to a sequence of sequences.

The flatMap operator, on the other hand, applies a transform method to each element of the source Observable, converting them to Observables. The elements of the Observables are then merged and sent out. It “squashes” (reduces dimension) it into an Observable sequence. This operator is very useful. For example, when the element of an Observable owns other Observables, we can send all the elements of the sub-Observables

  • flatMapLatest

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

  • flatMapFirst

FlatMapFirst is the opposite of flatMapLatest: flatMapFirst only receives the initial value event.

  • concatMap

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.

  • scan

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

  • groupBy

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.

  • filter

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

  • take

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

  • skip

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

  • distinctUntilChanged

This operator is used to filter out continuously repeated events.

  • single

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.

  • elementAt

This method implementation only handles events at a specified location.

  • ignoreElements

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.

  • takeLast

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

  • Sample

In addition to subscribes to the source Observable, Sample can also monitor another Observable, namely, notifier.

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.

  • debounce

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.

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

  • amb

When multiple Observables are passed to the AMB operator, it takes the first emitted element or Observable that generated the event, and emits only its element. And ignore the other Observables.

  • 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.

  • takeUntil

In addition to subscribing to the source Observable, the takeUntil method allows you to monitor another Observable, the Notifier.

If notifier issues a value or complete notification, the source Observable completes automatically and stops sending events.

  • skipWhile

This method is used to skip all previous events that meet the criteria.

Once an event that does not meet the criteria is encountered, it will not be skipped afterwards

  • skipUntil

In addition to subscribing to the source Observable, skipUntil can be used to monitor another Observable, namely notifier.

The opposite of takeUntil. The source Observable sequence events are skipped by default until notifier issues a value or complete notification.

  • startWith

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

  • merge

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

  • zip

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. 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
  • combineLatest

This method also merges multiple (two or more) Observable sequence elements.

Unlike ZIP, however, it merges the latest event element of each Observable sequence whenever a new event is emitted

  • withLatestFrom

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

  • switchLatest

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.

  • toArray

This operator converts a sequence into an array, sends it as a single event, and then terminates.

  • reduce

Reduce takes an initial value and an operation symbol.

Reduce aggregates a given initial value over each value in the sequence. Get a final result and send it as a single value.

  • concat

Concat merges (concatenates) multiple Observables into one Observable.

And the next Observable starts sending events only after the last One emits a Completed event