Blockchain ク gainst to the list

This article uses the current latest version of Xcode 13 + macOS Monterey + iOS15

Summary of the Operator

Publisher contains many operators in the Combine framework. Publisher operates on the event elements it emits through some method transformation called Operator. Publisher publishes the data, then Opeartor processes the data and returns a new Publisher. These operations are described below to help understand and use them.

Mapping Elements

map/tryMap

Similar to the Map operation in the Swift library, elements passed down from the Pulisher are converted using a closure function. TryMap is the same as the map operation except that you can throw an exception inside a closure.

The Map operation is shown below, converting each element into another:

Here’s an example:

let input = PassthroughSubject<Int.Never> ()let output = PassthroughSubject<Int.Never> ()let sub = input.map { value in
    return value * 2
}.subscribe(output)
output.sink(receiveValue: { print("Output: ".$0)})

input.send(1)
input.send(2)
input.send(3)
Copy the code
  • Create a PassthroughSubject as the Input
  • Input performs the map operation, multiplying each element by 2
  • Attach the map publisher of the Input to the Output Subject
  • The subscription bysinkTo the input and output
  • Input Sends data

The output is as follows:

Output: 2
Output: 4
Output: 6
Copy the code

mapError

MapError is similar to Map, except that Map converts publisher to publish event elements, whereas mapError converts Publisher to throw exceptions.

For example, when data 3 is received, error1 is thrown and error1 is converted to error2

enum TestError: Error{
    case error1
    case error2
}

let input = PassthroughSubject<Int.Never> ()let output = PassthroughSubject<Int.TestError> ()let sub = input.tryMap { value in
    if value = = 3 {
        throw TestError.error1
    }
    return value * 2
}
.mapError({ _ in
    return TestError.error2
})
.subscribe(output)

output.sink(receiveCompletion: {print("Output Completed:".$0)}, receiveValue: {print("Output Value:".$0)})

input.send(1)
input.send(2)
input.send(3)
Copy the code
  • The customerror1anderror2
  • Input performs tryMap and is thrown when value == 3error1
  • throughmapErrorConvert error1 toerror2And append to output
  • Input Sends data

Output:

Output Value: 2
Output Value: 4
Output Completed: failure(__lldb_expr_111.TestError.error2)
Copy the code

When input sent 3, Output received a test. error2 error.

replaceNil

Replace the nil data for the event element sent by Publisher.

The replaceNil process is shown below:

Here’s an example:

let input = PassthroughSubject<Int? .Never> ()let output = PassthroughSubject<Int.Never> ()let v = input.replaceNil(with: 5).subscribe(output)

output.sink(receiveCompletion: {print("Output Completed:".$0)}, receiveValue: {print("Output Value:".$0)})

input.send(1)
input.send(nil)
input.send(3)

Copy the code
  • The input toreplaceNilThe operation converts nil to 5 and appends to Output
  • Input emits 1, nil, 3, respectively

Output:

Output Value: 1
Output Value: 5
Output Value: 3
Copy the code

Output Received 1, 5, 3

scan

Scan is similar to the reduce operation in the Swift standard library. The first parameter is an initial value and the second parameter is a closure. Pass the event element sent from Publisher into the closure along with the value returned from the previous closure and return the new value.

The scan event flow is as follows:

Here’s an example:


let input = PassthroughSubject<Int.Never> ()let output = PassthroughSubject<Int.Never> ()let sub = input.scan(0, { $0 + The $1}).subscribe(output)

output.sink(receiveValue: {print("Output vaule:".$0)})

input.send(1)
input.send(2)
input.send(3)
Copy the code
  • Input Performs scan operations
  • Input sends 1, 2, and 3 respectively

Output:

Output vaule: 1
Output vaule: 3
Output vaule: 6
Copy the code

Ouptut received: 1, 3, 6

Filtering Elements

filter/tryFilter:

Filter is similar to the filter in the Swift standard library, passing a closure returns true to accept the element, false to filter out the element. TryFilter can throw an exception in the closure.

The filter process is as follows:

Here’s an example:

let input = PassthroughSubject<Int.Never> ()let output = PassthroughSubject<Int.Never> ()let sub = input.filter{$0 > 1}.subscribe(output)
output.sink(receiveValue: {print("Output vaule:".$0)})

input.send(1)
input.send(2)
input.send(3)
Copy the code
  • Filter out event elements less than or equal to 1

Output:

Output vaule: 2
Output vaule: 3
Copy the code

Output is only 2 and 3

compactMap/tryCompactMap

CompactMap converts event elements received from Publisher and filters out values that return nil. TryCompactMap can throw an exception in a closure.

Here’s an example:

let input = PassthroughSubject<String.Never> ()let output = PassthroughSubject<Int.Never> ()let sub = input.compactMap{Int($0)}.subscribe(output)

output.sink(receiveValue: {print("Output vaule:".$0)})

input.send("1")
input.send("a")
input.send("2")

Copy the code
  • Input The input character string passescompactMapConvert to Int

Output:

Output vaule: 1
Output vaule: 2
Copy the code

Output outputs 1 and 2, Int(“a”) returns nil filtered out by compactMap

removeDuplicates/tryRemoveDuplicates

RemoveDuplicates filter out event elements that are the same as the one it received last time. Custom comparison methods can be passed in a closure for comparison. TryRemoveDuplicates can throw an exception in an incoming comparison closure.

The process is as follows:

Here’s an example:

let input = PassthroughSubject<Int.Never> ()let output = PassthroughSubject<Int.Never> ()let sub = input.removeDuplicates().subscribe(output)

output.sink(receiveValue: {print("Output vaule:".$0)})

input.send(1)
input.send(2)
input.send(2)
input.send(3)
input.send(3)
input.send(1)
Copy the code
  • Input continuous input 1,2, 3,3,1
  • removeDuplicatesoperation

Output:

Output vaule: 1
Output vaule: 2
Output vaule: 3
Output vaule: 1
Copy the code

Output filters out consecutive identical inputs. The first and last 1 are not consecutive inputs so they are not filtered.

relpaceEmpty

If the Publisher does not publish any events, send(Completion:.finished), and the relpaceEmpty parameter content is returned.

Such as:

let input = PassthroughSubject<Int.Never> ()let output = PassthroughSubject<Int.Never> ()let sub = input.replaceEmpty(with: 42).subscribe(output)
output.sink(receiveValue: {print("Output vaule:".$0)})

input.send(completion: .finished)

Copy the code

Output:

Output vaule: 42
Copy the code

If Publisehr ends directly, Ouput receives the value replaced by relpaceEmpty.

Modify the finished code to add a line before sending data:

.
input.send(1)
input.send(completion: .finished)
Copy the code

Output:

Output vaule: 1
Copy the code

When Publisher events are emitted, replaceEmpty does not replace them.

replaceError

ReplaceError replaces an exception thrown upstream with an incoming event element. ReplaceError replaces errors with normal content, and mapError replaces exceptions with exceptions.

Here’s an example:

enum TestError: Error{
    case error
}

let input = PassthroughSubject<Int.TestError> ()let output = PassthroughSubject<Int.Never> ()let sub = input.tryMap({ value -> Int in
    guard value < 2 else{
        throw TestError.error
    }
    return value
})
.replaceError(with: 42)
.subscribe(output)


output.sink(receiveValue: {print("Output vaule:".$0)})

input.send(1)
input.send(2)
input.send(3)

Copy the code
  • TryMap throws an exception if the event element received is greater than or equal to 2
  • withreplaceErrorReplace the exception with 42

Output:

Output vaule: 1
Output vaule: 42
Copy the code
  • An exception is raised when input emits 2, and ouput receives the replaced value 42
  • Failed to receive because an exception was thrown when issuing 2.