func filter(_ isIncluded: @escaping (Self.Output) -> Bool) -> Publishers.Filter<Self>
클로저에 맞는 항목만 다시 publish 하는 operator
let numbers: [Int] = [1, 2, 3, 4, 5]
cancellable = numbers.publisher
.filter { $0 % 2 == 0 }
.sink { print("\($0)", terminator: " ") }
// Prints: "2 4"
func tryFilter(_ isIncluded: @escaping (Self.Output) throws -> Bool) -> Publishers.TryFilter<Self>
isIncluded
클로저가 항목을 다시 publish 할지 여부를 리턴하거나 에러를 던짐.
클로저가 에러를 던지면 publisher는 에러와 함께 실패한다.
struct ZeroError: Error {}
let numbers: [Int] = [1, 2, 3, 4, 0, 5]
cancellable = numbers.publisher
.tryFilter{
if $0 == 0 {
throw ZeroError()
} else {
return $0 % 2 == 0
}
}
.sink(
receiveCompletion: { print ("\($0)") },
receiveValue: { print ("\($0)", terminator: " ") }
)
// Prints: "2 4 failure(DivisionByZeroError())".
func removeDuplicates(by predicate: @escaping (Self.Output, Self.Output) -> Bool) -> Publishers.RemoveDuplicates<Self>
이전 항목과 다른 항목만 publish 하는 operator
predicate
: 두 항목이 같은지 비교하는 클로저true
를 반환함사용자가 연속으로 같은 문자를 입력했을 때, 중복된 문자를 무시하고 싶을 때 유용할 듯
Equatable
을 구현하지 않은 타입들을 비교하거나 Equatable
을 구현한 것과 다르게 값을 비교하고 싶을 때 사용struct Point {
let x: Int
let y: Int
}
let points = [Point(x: 0, y: 0), Point(x: 0, y: 1),
Point(x: 1, y: 1), Point(x: 2, y: 1)]
cancellable = points.publisher
.removeDuplicates { prev, current in
// Considers points to be duplicate if the x coordinate
// is equal, and ignores the y coordinate
prev.x == current.x
}
.sink { print("\($0)", terminator: " ") }
// Prints: Point(x: 0, y: 0) Point(x: 1, y: 1) Point(x: 2, y: 1)
struct RemoveDuplicates<Upstream> where Upstream : Publisher
이전 항목과 일치하지 않는 항목들만 publish하는 publisher
func tryRemoveDuplicates(by predicate: @escaping (Self.Output, Self.Output) throws -> Bool) -> Publishers.TryRemoveDuplicates<Self>
predicate
클로저가 Boolean 값을 반환하거나 에러를 던짐.struct BadValuesError: Error {}
let numbers = [0, 0, 0, 0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
cancellable = numbers.publisher
.tryRemoveDuplicates { first, second -> Bool in
if (first == 4 && second == 4) {
throw BadValuesError()
}
return first == second
}
.sink(
receiveCompletion: { print ("\($0)") },
receiveValue: { print ("\($0)", terminator: " ") }
)
// Prints: "0 1 2 3 4 failure(BadValuesError()"
func ignoreOutput() -> Publishers.IgnoreOutput<Self>
모든 upstream 항목들을 무시하지만 upstream publisher의 completion 상태(finished or failed)는 전달해주는 operator
struct NoZeroValuesAllowedError: Error {}
let numbers = [1, 2, 3, 4, 5, 0, 6, 7, 8, 9]
cancellable = numbers.publisher
.tryFilter({ anInt in
guard anInt != 0 else { throw NoZeroValuesAllowedError() }
return anInt < 20
})
.ignoreOutput()
.sink(receiveCompletion: {print("completion: \($0)")},
receiveValue: {print("value \($0)")})
// Prints: "completion: failure(NoZeroValuesAllowedError())"
위 예시에서 ignoreOutput()
operator는 1~5까지는 정상적으로 전달받지만 downstream으로 publish되지 않는다.
0
이 publish 되었을 때는 NoZeroValuesAllowedError
와 함께 stream이 종료된다.
이 Publisher의 Output은 Never
이다.
절대 항목을 방출하지 않기 때문!
func first() -> Publishers.First<Self>
스트림의 첫 번째 항목을 publish하고 종료하는 operator
first()
operator가 바로 upstream으로부터 unlimited
를 요청함first()
가 값을 받기 전에 upstream이 종료되면 어떤 값도 방출하지 않고 종료된다.let numbers = (-10...10)
cancellable = numbers.publisher
.first()
.sink { print("\($0)") }
// Print: "-10"
func first(where predicate: @escaping (Self.Output) -> Bool) -> Publishers.FirstWhere<Self>
클로저 안의 내용을 만족하는 스트림의 첫 번째 항목을 publish하고 종료하는 operator
predicate
: 한 항목을 파라미터로 받고, 그 항목을 publish 할지 여부를 리턴하는 클로저“모두 무시”라는 표현 때문에 이후 값도 다 받긴 하지만 그냥 무시하는 건가 싶었는데 첫 번째 값을 찾으면 바로 종료되는 것 같다.
——— Example of: first(where:) ———
numbers: receive subscription: (1...9)
numbers: request unlimited
numbers: receive value: (1)
numbers: receive value: (2)
numbers: receive cancel
2
Completed with: finished
let numbers = (-10...10)
cancellable = numbers.publisher
.first { $0 > 0 }
.sink { print("\($0)") }
// Prints: "1"
func tryFirst(where predicate: @escaping (Self.Output) throws -> Bool) -> Publishers.TryFirstWhere<Self>
predicate
클로저가 Boolean 값을 반환하거나 에러를 던질 수 있다. 클로저가 에러를 던지면 publisher는 실패한다.
let numberRange: ClosedRange<Int> = (-1...50)
numberRange.publisher
.tryFirst {
guard $0 < 99 else {throw RangeError()}
return true
}
.sink(
receiveCompletion: { print ("completion: \($0)", terminator: " ") },
receiveValue: { print ("\($0)", terminator: " ") }
)
// Prints: "-1 completion: finished"
// If instead the number range were ClosedRange<Int> = (100...200), the tryFirst operator would terminate publishing with a RangeError.
func last() -> Publishers.Last<Self>
스트림이 종료된 후에 스트림의 마지막 항목을 publish 한다.
let numbers = (-10...10)
cancellable = numbers.publisher
.last()
.sink { print("\($0)") }
// Prints: "10"
struct Last<Upstream> where Upstream : Publisher
스트림이 종료될 때까지 기다렸다가 마지막 항목을 publish하는 publisher
→ 그래서 upstream publisher는 반드시 언젠가 종료되는 publisher여야 한다!
func last(where predicate: @escaping (Self.Output) -> Bool) -> Publishers.LastWhere<Self>
upstream이 종료된 후에 클로저 내의 조건을 만족하는 스트림의 마지막 항목을 publish하는 operator
let numbers = (-10...10)
cancellable = numbers.publisher
.last { $0 < 6 }
.sink { print("\($0)") }
// Prints: "5"
func tryLast(where predicate: @escaping (Self.Output) throws -> Bool) -> Publishers.TryLastWhere<Self>
predicate
클로저가 Boolean 값을 리턴하거나 에러를 던진다.struct RangeError: Error {}
let numbers = [-62, 1, 6, 10, 9, 22, 41, -1, 5]
cancellable = numbers.publisher
.tryLast {
guard 0 != 0 else {throw RangeError()}
return true
}
.sink(
receiveCompletion: { print ("completion: \($0)", terminator: " ") },
receiveValue: { print ("\($0)", terminator: " ") }
)
// Prints: "5 completion: finished"
// If instead the numbers array had contained a `0`, the `tryLast` operator would terminate publishing with a RangeError."
func drop<P>(untilOutputFrom publisher: P) -> Publishers.DropUntilOutput<Self, P> where P : Publisher, Self.Failure == P.Failure
파라미터로 받은 publisher로부터 항목을 받기 전까지는 upstream publisher의 항목을 무시하는 operator
operator를 호출한 publisher를 A, 파라미터로 받은 publisher를 B라고 하면..
After this publisher receives a subscription from the upstream publisher, it passes through backpressure requests from downstream to the upstream publisher. If the upstream publisher acts on those requests before the other publisher produces an item, this publisher drops the elements it receives from the upstream publisher.
let upstream = PassthroughSubject<Int,Never>()
let second = PassthroughSubject<String,Never>()
cancellable = upstream
.drop(untilOutputFrom: second)
.sink { print("\($0)", terminator: " ") }
upstream.send(1)
upstream.send(2)
second.send("A")
upstream.send(3)
upstream.send(4)
// Prints "3 4"
struct DropUntilOutput<Upstream, Other> where Upstream : Publisher, Other : Publisher, Upstream.Failure == Other.Failure
두 번째 publisher의 항목을 받기 전까지는 upstream publisher의 항목을 무시하는 publisher
func dropFirst(_ count: Int = 1) -> Publishers.Drop<Self>
특정 개수의 항목들을 drop 한 후에 항목들을 publish 하는 operator
count
의 기본값은 1count
로 전달받은 개수만큼의 항목은 publish하지 않는 publisher를 리턴한다.let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
cancellable = numbers.publisher
.dropFirst(5)
.sink { print("\($0)", terminator: " ") }
// Prints: "6 7 8 9 10 "
func drop(while predicate: @escaping (Self.Output) -> Bool) -> Publishers.DropWhile<Self>
클로저가 false를 리턴할 때까지 upstream publisher의 값을 무시하고, 나머지 항목들을 publish하는 operator
predicate
: publisher로부터 받은 항목을 drop 할지 여부를 반환하는 클로저let numbers = [-62, -1, 0, 10, 0, 22, 41, -1, 5]
cancellable = numbers.publisher
.drop { $0 <= 0 }
.sink { print("\($0)") }
// Prints: "10 0, 22 41 -1 5"
한 번 클로저가 false를 반환하고 나면 그 이후 모든 값들을 publish한다.
func tryDrop(while predicate: @escaping (Self.Output) throws -> Bool) -> Publishers.TryDropWhile<Self>
클로저가 Boolean 값을 리턴하거나 에러를 던진다.
클로저가 에러를 던지면 publisher는 에러와 함께 실패한다.
false
를 반환하면 에러도 던지지 않고 무조건 publish 한다. → filter
는 조건에 만족하는 항목을 만난 후에도 계속 클로저의 조건을 확인하지만, drop(while:)
은 한 번 클로저의 조건을 만족하면 그 이후에는 조건을 다시 확인하지 않는다. struct RangeError: Error {}
var numbers = [1, 2, 3, 4, 5, 6, -1, 7, 8, 9, 10]
let range: CountableClosedRange<Int> = (1...100)
cancellable = numbers.publisher
.tryDrop {
guard $0 != 0 else { throw RangeError() }
return range.contains($0)
}
.sink(
receiveCompletion: { print ("completion: \($0)") },
receiveValue: { print ("value: \($0)") }
)
// Prints: "-1 7 8 9 10 completion: finished"
// If instead numbers was [1, 2, 3, 4, 5, 6, 0, -1, 7, 8, 9, 10], tryDrop(while:) would fail with a RangeError.
func prefix(_ maxLength: Int) -> Publishers.Output<Self>
파라미터로 전달한 개수만큼의 항목을 publish한다.
⇒ upstream publisher가 방출할 수 있는 값의 개수를 제어
prefix라는 이름 그대로 먼저 항목을 publish 한 후에 완료한다. dropFirst와 반대되는 개념!
maxLength
: publish할 항목의 최대 개수let numbers = (0...10)
cancellable = numbers.publisher
.prefix(2)
.sink { print("\($0)", terminator: " ") }
// Prints: "0 1"
func prefix(while predicate: @escaping (Self.Output) -> Bool) -> Publishers.PrefixWhile<Self>
클로저의 조건을 만족하는 값을 방출할 때까지만 다시 publish하는 operator
predicate
: 하나의 항목을 파라미터로 받고 계속 publish 해야 하는지 여부를 반환하는 클로저false
를 리턴하면 publisher는 종료된다.let numbers = (0...10)
numbers.publisher
.prefix { $0 < 5 }
.sink { print("\($0)", terminator: " ") }
// Prints: "0 1 2 3 4"
func tryPrefix(while predicate: @escaping (Self.Output) throws -> Bool) -> Publishers.TryPrefixWhile<Self>
struct OutOfRangeError: Error {}
let numbers = (0...10).reversed()
cancellable = numbers.publisher
.tryPrefix {
guard $0 != 0 else {throw OutOfRangeError()}
return $0 <= numbers.max()!
}
.sink(
receiveCompletion: { print ("completion: \($0)", terminator: " ") },
receiveValue: { print ("\($0)", terminator: " ") }
)
// Prints: "10 9 8 7 6 5 4 3 2 1 completion: failure(OutOfRangeError()) "