One of the most important concepts in RxSwit is called Observable, which we can translate into sequences, Observable sequences, and so on

Flow, sequence, observable sequence, it’s all the same thing. It’s something that emits events continuously.

Methods are also called operators in Rx

How do YOU create a signal flow

  • Just way

    let observable = Observable.just(1)

    Just is a static method of Observab

    This method creates a signal flow that emits only one element

  • Method of

    Observable.of(1, 2, 3, 4)

    The just method can accept only one element, and you can use the OF method if more than one element needs to be sent through the signal stream

    Usage scenario: If you want to iterate over an array, you can use the of method instead of the for in loop

  • Method the from

    Observable.from([1, 2, 3, 4])

    The FROM method also creates a signal flow, but it takes an array and sends out the elements of the array one by one

    Usage scenario: If you are passing an array instead of one element at a time, you can use the signal stream generated by the FROM method for traversal

How do you listen to a signal stream

We are familiar with NotificationCenter without RxSwift. In notification mode, we want to listen for a notification and will listen for the specified notification through addObserver().

In RxSwift it is similar to the above except that we replace addObserver() with subscribe().

But unlike notifications, which we generally use as singletons, each source of RxSwift is separate.

If a signal is not subscribed, it does not send events and no internal operations are performed.

Monitoring operation is like establishing a channel between the signal source and the observer. After monitoring, there will be this channel, and the signal source will send events through the channel.

The event is sent like a stream. We can handle each event in this event stream.

A stream can be listened to with the subscribe() method, as shown in the following example


	let observable = Observable.of(1.2.3)

	observable.subscribe{ event in 

		print(event)

	}

Copy the code

The above code will print


	next(1)

	next(2)

	next(3)

	completed

Copy the code

Click subscribe to see that its closure takes a value of type Event. Each time the stream sends a signal, it wraps the value in the Next Event and sends it out

However, we usually use internally wrapped values, so it can be used in the following way


	observable.subscribe { event in 

		if let value = event.element {

			print(value)

		}

	} 

Copy the code

The Event has an optional Element attribute, and since only the Next Event has an Element, you can unpack it to get the internal value

Because subscribes to events are used frequently, unpacking each time is a bit cumbersome, so Rx provides a shortcut that listens for each event with an operator

observable.subscribe { onNext: { element in print(element) }, onCompleted: { print("completed!" )}}Copy the code

Termination and release of a signal flow

Again: a signal source will do nothing if no observer is listening.

It is this listening action that triggers the source to send events until an error or completed event is sent that terminates the signal (the source is disconnected from the observer, and subsequent events are not received).

In addition to sending an error or completed event, we can manually destroy the source by canceling the listening, thus terminating the event stream.

Write a code to look at the termination of the signal flow


	let observable = Observable.of("A", "B", "C")

	let subscription = observable.subscribe { event in 

		print(event)

	}

Copy the code

Code interpretation

  1. A signal stream of strings is created

  2. The signal was monitored. Also, the return value of this source, Disposable, is saved as a constant subscription

  3. Print each event inside the closure

The code above does not release the source. This means that all signals of the signal flow have been sent, but there is still a channel between the listener and the source. So there’s no point here. It also introduces the problem of memory leaks.

If you want to actively unsubscribe, you can have the Disposable Subscription call dispose() method. When the source is released, it will not send any more events.


subscription.dispose()

Copy the code

Handling the destruction of each signal’s subscription individually is too cumbersome, so RxSwift provides a DisposeBag type

A DisposeBag contains all of the disposable’s that need to be released

Disposed (by:) usually adds the subscriber to the DisposeBag, which, when released, terminates the stream by calling the dispose() method for each subscriber in the package (disposable).

So a common pattern is this

	let disposeBag = DisposeBag()

	Observable.of("A", "B", "C").subscribe{ 

		print($0)

	}.disposed(by: disposeBag)



Copy the code

annotation

  1. Start by creating a releaser package

  2. Create a signal flow

  3. Listen to this signal stream and print the event sent with the default parameter $0

  4. Add the returned disposable to the release package

The question is: Where did the destroyer come from? Why do we get this after we set up a listen with the subscribe() method? What does the dipose() method do? .

This is seen from the original signal creation method, create()

The create method

We have seen several ways to create signal sources before, but all of them automatically send out events. We have no active control over the sending of events. The create method manually sends out all available events.

A simple example of create looks like this:


	Observable<String>.create { observer in 

		observer.onNext("1")

		observer.onCompleted()

		return Disposables.create()

	}

Copy the code

The create method takes a closure whose parameter name is SUBSCRIBE. So when does this closure execute.

As you can see from the code comments for the create method, this closure is an implementation of the SUBSCRIBE () method.

So that means it’s executed in the subscribe() method and it’s executed.

This explains why a signal does nothing if it does not generate a subscription.

The next step is to look at the parameters and return values of the closure

The closure takes an AnyObserver argument and returns a Disposable

When we talked about the termination of the stream we saw that the return value of subscribe() is a Disposable, the Disposable that was created and returned here.

AnyObserver is a generic that adds values to the signal flow that will be sent to the subscriber.

OnNext () is a shortcut to on(.next(_:))

And finally returns a Disposable to indicate what to do when the stream terminates or is destroyed, in this case there is nothing to clean up, so an empty Disposable is returned

I understand that this Disposable has nothing to do with Observable Observer. What it does is clean up some additional resources.

If completed or error is not sent, the flow will not stop, and disposable will not be executed, and the signal will not be released. (The channel between the observer and the source does not break)

What other ways can you create a signal flow

  • The empty methods

    let observable = Observable<Void>.empty() observable.subscribe { onNext: { element in print(element) }, onCompleted: { print("completed!" )}}Copy the code

    The example above simply prints Completed!

    The Observable.Empty () method creates an empty signal stream that sends the complete event directly

    When do you use empty() to create a signal stream: When you need a signal to tell something that it’s done, consider creating an empty signal through empty()

  • Range method

    	Observable.range(start: 1, count: 10).subscrbe(
    
    		onNext: { value in 
    
    			print(value)
    
    		}
    
    	)
    Copy the code

    The range method creates a signal stream that starts at the start value and sends a signal each time by adding one to the previous value

    When you need to quickly generate a sequence, consider using the range method

  • Never approach

    Never Indicates that the created signal source does not send any event. When listening, a channel is established between the listener and the signal, but no events are sent.

    We haven’t found the exact usage scenarios yet.

Special signal

These special signals are less manipulable than ordinary signal streams. Usually they have only one ability to perform.

Wherever a special signal is used, it can be replaced by an ordinary signal.

These special signals are meant to simplify the code

Three special signals are introduced in RxSwift: Single, Maybe and Completable

  • Single

    Single will only emit success(value) or error(error) events.

    Success (value) is actually a combination of next and Completed. The characteristic of this signal is that both the final state and the resulting value are sent

    Usage scenario: For example, for a data processing, we want to get the final processing state and result (for example, data download, the final required state and the result of downloading, or for example, reading a file from the hard disk, we finally need the result of reading and the content of the file read). You can use Single

Enum FileReadError: Error {case fileNotFound, unreadable, encodingFailded} // Define a method to reada file func loadDiskFile(path: String) -> Single<String> { return Single<String>.create { let disposable = Disposables.create() guard let path = Bundle.main.path(forResource: path, ofType: "txt") else { single(.error(FileReadError.fileNotFound)) return disposable } guard let data = FileManager.default.contents(atPath: path) else { single(.error(FileReadError.unreadable)) return disposable } guard let contents = String(data: data, encoding: .utf8) else { single(.error(FileReadError.encodingFailed)) return disposable } single(.success(contents)) return // loadDiskFile("sample").subscribe(switch $0 {case.success (let content): print(content) case .error(let error): print(error) } ).disposed(by: DisposeBag())Copy the code
  • Completable

    Completable sends only one completed or error(error) event

    It sends this event that doesn’t carry a value

    If you only care about the result of an operation, consider using the Completable signal

    Usage scenario: When you write a piece of data to a hard disk, you only need to check whether the data is successfully written. And to do that without giving us anything back, just use Completable, right

  • Mayby

    Maybe is an operator that combines Completable and Single. It can either send the state of the result and the result value, success(value), error(error), as Single does, or just the state of the result, Completable

  • The debug operator

    When debugging Rx code, you can use the debug operator to look for bugs in the code execution

    This operator prints information for each event

    This method takes several optional arguments, perhaps the most useful of which is that it allows us to add a unique string that can be output along with it

More special signals will follow

Summary of the section above

To this point, we have described above what signal flow is, how to create a signal, how to listen for a signal and how to do something with it.

But these signals are read-only in nature, so we can only listen for them and get the events they generate. (Or rather, these signals are more disposable: it processes something, sends the signal, and then the signal is done.)

During the development process, it is probably more common for us to manually add a signal to the signal stream at runtime to send to listeners.

This is the Subject to be introduced next