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 by
sink
To 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 custom
error1
anderror2
- Input performs tryMap and is thrown when value == 3
error1
- through
mapError
Convert error1 toerror2
And 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 to
replaceNil
The 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 passes
compactMap
Convert 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
removeDuplicates
operation
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
- with
replaceError
Replace 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.