반응형
이전글
- 2021/01/03 - [Reactive Programming] - [Combine 책 정리] Chapter1. Hello, Combine!
- 2021/01/06 - [Reactive Programming] - [Combine 책 정리] Chapter2. Hello, Combine!
- 2021/01/12 - [Reactive Programming] - [Combine 책 정리] Chatper 3: Transforming Operators
이번 챕터에서는 특별히 신선한 내용은 없었다.
실제 사례에서 여러 operator들을 잘 조합해보는게 중요할 듯
Filtering basics
example(of: "filter") {
let numbers = (1...10).publisher
numbers
.filter { $0.isMultiple(of: 3) } // collection에 filter 쓰는거랑 똑같음
.sink(receiveValue: { n in
print("\(n) is a multiple of 3")
})
.store(in: &subscriptions)
}
——— Example of: filter ———
3 is a multiple of 3
6 is a multiple of 3
9 is a multiple of 3
example(of: "removeDuplicates") {
let words = "hey hey hey there! want to listen to mister mister ?"
.components(separatedBy: " ")
.publisher
words
.removeDuplicates() // 연속해서 같은 value가 오면 나중에 오는 value는 무시해줌
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: removeDuplicates ———
hey
there!
want
to
listen
to
mister
?
Value가 Equatable을 준수하지 않는 경우
조건을 직접 넣어서 구현 가능
example(of: "removeDuplicates2") {
struct CustomValue {
let value: String
}
let words = "hey hey hey there! want to listen to mister mister ?"
.components(separatedBy: " ")
.map { CustomValue(value: $0) }
.publisher
words
.removeDuplicates(by: { $0.value == $1.value }) // Equatable을 준수하지 않는 객체인 경우에는 비교문으로 구현 가능
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: removeDuplicates2 ———
CustomValue(value: "hey")
CustomValue(value: "there!")
CustomValue(value: "want")
CustomValue(value: "to")
CustomValue(value: "listen")
CustomValue(value: "to")
CustomValue(value: "mister")
CustomValue(value: "?")
Compacting and ignoring
example(of: "compactMap") {
let strings = ["a", "1.24", "3", "def", "45", "0.23"].publisher
strings
.compactMap { Float($0) } // nil이면 무시해줌
.sink(receiveValue: {
print($0)
})
.store(in: &subscriptions)
}
——— Example of: compactMap ———
1.24
3.0
45.0
0.23
ignoreOutput은 complete 때만 관심이 있을 때 사용하면 될 듯
// 이걸 언제 쓸지 잘 모르겠음
example(of: "ignoreOutput") {
let numbers = (1...10_000).publisher
numbers
.ignoreOutput()
.sink(receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: ignoreOutput ———
Completed with: finished
Finding values
first(where:)
lazy한 특성
만족하는 조건이 나오면, 더 이상 검사를 실행하지 않음
example(of: "first(where:)") {
let numbers = (1...9).publisher
numbers
.print("numbers")
.first(where: { $0 % 2 == 0 }) // lazy 효과를 내는데, 유효한 value 하나를 충족하면 emit 후 complete됨
.sink(receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— 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
last(where:)
greedy한 특성. 모든 value를 검사함
example(of: "last(where:)") {
let numbers = (1...9).publisher
numbers
.last(where: { $0 % 2 == 0 }) // greedy. 모든 value를 검사함
.sink(receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: last(where:) ———
8
Completed with: finished
example(of: "last(where:) 2") {
let numbers = PassthroughSubject<Int, Never>()
numbers
.last(where: { $0 % 2 == 0 })
.sink(receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) })
.store(in: &subscriptions)
numbers.send(1)
numbers.send(2)
numbers.send(3)
numbers.send(4)
numbers.send(5)
numbers.send(completion: .finished)
}
——— Example of: last(where:) 2 ———
4
Completed with: finished
Dropping values
example(of: "dropFirst") {
let numbers = (1...10).publisher
numbers
.dropFirst(8)
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: dropFirst ———
9
10
drop(while:) 도 lazy한 특성을 띄는데, print("x")가 다섯번만 실행되는걸 알 수 있다.
example(of: "drop(while:)") {
let numbers = (1...10).publisher
numbers
.drop(while: { // * 조건 만족하는게 나올때까지 drop
print("x") // * 한번 조건 만족하면 실행되지 않음
return $0 % 5 != 0
})
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: drop(while:) ———
x
x
x
x
x
5
6
7
8
9
10
drop(untilOutputFrom:)
이건 rx에서도 비슷한 기능을 유용하게 썼었음
viewController에서 화면이 나타나고 나서 어떤 작업을 하고 싶을 때 사용 가능
example(of: "drop(untilOutputFrom:)") {
let isReady = PassthroughSubject<Void, Never>()
let taps = PassthroughSubject<Int, Never>()
taps
.drop(untilOutputFrom: isReady)
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
(1...5).forEach { n in
taps.send(n)
if n == 3 {
isReady.send()
}
}
}
——— Example of: drop(untilOutputFrom:) ———
4
5
Limiting values
example(of: "prefix") {
let numbers = (1...10).publisher
numbers
.prefix(2) // 2개만 value를 받고 이후로는 무시. lazy
.sink(receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: prefix ———
1
2
Completed with: finished
example(of: "prefix(while:)") {
let numbers = (1...10).publisher
numbers
.prefix(while: { $0 < 3 }) // 한번 조건을 만족하면, complete
.sink(receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) })
.store(in: &subscriptions)
}
——— Example of: prefix(while:) ———
1
2
Completed with: finished
example(of: "prefix(untilOutputFrom:)") {
let isReady = PassthroughSubject<Void, Never>()
let taps = PassthroughSubject<Int, Never>()
taps
.prefix(untilOutputFrom: isReady)
.sink(receiveCompletion: { print("Completed with: \($0)") },
receiveValue: { print($0) })
.store(in: &subscriptions)
(1...5).forEach { n in
taps.send(n)
if n == 2 {
isReady.send()
}
}
}
——— Example of: prefix(untilOutputFrom:) ———
1
2
Completed with: finished
Challenge
1. 처음 50개는 스킵
2. 50개 이후 20개까지만 받음
3. 짝수만 받음
(1...100)
.publisher
.dropFirst(50)
.prefix(20)
.filter { $0 % 2 == 0 }
.sink(receiveValue: { print($0) })
.store(in: &subscriptions)
52
54
56
58
60
62
64
66
68
70
반응형
'iOS > Combine' 카테고리의 다른 글
[Combine 책 정리] Chapter 6: Time Manipulation Operators (0) | 2021.01.19 |
---|---|
[Combine 책 정리] Chapter 5: Combining Operators (0) | 2021.01.18 |
[Combine 책 정리] Chatper 3: Transforming Operators (0) | 2021.01.12 |
[Combine 책 정리] Chapter 2: Publishers & Subscribers (0) | 2021.01.06 |
[정리] 토비의 봄 TV - 스프링 리액티브 프로그래밍 (0) | 2021.01.05 |