반응형
Transforming Operator
Combine에서 Operator는 Publisher를 가공해 다른 형태나 구성으로 변경해주는 역할을 한다. Upstream으로부터 전달받은 데이터를 가공하여 downstream으로 전달하는 것이다.
그 중 데이터의 형태(타입)를 바꿔주는 Operator(Transforming Operator) 정리해볼 것이다.
collect
Example
["A","B","C","D","E"].publisher.collect(3).sink {
print($0)
}
Output
["A", "B", "C"]
["D", "E"]
- Input 데이터를 모아서 Array로 한번에 반환하도록 처리한다.
- 파라미터로 숫자를 넣어서 몇개를 하나로 묶을지도 결정할 수 있다. (default는 모든 데이터를 한번에 묶는 것이다. 이 경우 complete 될 때까지 무한정 array를 채울 수 있기 때문에 유의해야 한다.)
- 파라미터에 주어진 숫자를 채우지못하고 남는 데이터는 그것들끼리만 반환된다.
map
Example 1
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
[123,45,67].publisher.map {
formatter.string(from: NSNumber(integerLiteral: $0)) ?? ""
}.sink {
print($0)
}
Output 1
one hundred twenty-three
forty-five
sixty-seven
- 기존의 map 함수와 비슷한 역할을 한다. 특정 타입의 Array를 전혀 다른 형태의 Array로 변환할 수 있다.
Example 2
struct Point {
let x: Int
let y: Int
}
let publisher = PassthroughSubject<Point, Never>()
publisher.map(\.x, \.y).sink { x, y in
print("x is \(x) and y is \(y)")
}
publisher.send(Point(x: 2, y: 10))
Output 2
x is 2 and y is 10
- map에서 KeyPath를 사용해 특정 value를 바로 가져올 수도 있다
- 3개까지만 가능하다.
flatMap
Example
struct School {
let name: String
let noOfStudents: CurrentValueSubject<Int, Never>
init(name: String, noOfStudents: Int) {
self.name = name
self.noOfStudents = CurrentValueSubject(noOfStudents)
}
}
let citySchool = School(name: "Fountain Head School", noOfStudents: 100)
let school = CurrentValueSubject<School,Never>(citySchool)
school
.flatMap {
$0.noOfStudents
}
.sink {
print($0)
}
let townSchool = School(name: "Town Head School", noOfStudents: 45)
school.value = townSchool
citySchool.noOfStudents.value += 1
townSchool.noOfStudents.value += 10
Output
100
45
101
55
- 여러개의 publisher upstream을 하나의 단일 downstream으로 변환한다.
- 다차원 구조의 publisher가 존재할 경우 이를 하나의 단일 publisher 형태로 변환하기 때문에 내부에 존재하는 publisher에 대한 발행도 받아올 수 있다. (예시참고)
- downstream의 단일 publisher를 업데이트할 때 기존의 publisher를 버퍼링한다.
- cf. maxPublishers 라는 파라미터를 제공하는데, 이는 버퍼링하는 최대 publisher 개수를 설정한다.
replaceNil
Example
["A","B",nil,"C"].publisher.replaceNil(with: "*")
.sink {
print($0)
}
Output
Optional("A")
Optional("B")
Optional("*")
Optional("C")
- nil을 특정값으로 변환하여 반환하도록 변경한다.
replaceEmpty
Example
let empty = Empty<Int, Never>()
empty
.replaceEmpty(with: 1)
.sink(receiveCompletion: { print($0) }, receiveValue: { print($0) })
Output
1
finished
- upstream에서 value가 emit되지않고 completion이 수행되면 value를 하나 넣어준다.
scan
Example
let publisher = (1...10).publisher
publisher.scan([]) { numbers, value -> [Int] in
numbers + [value]
}.sink {
print($0)
}
Output
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7, 8]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
- value를 누적해서 원하는 형태로 변환 후 내보낸다.
- scan operator의 파라미터로 초기값을 넣고, 클로저에서는 이에 대한 처리를 수행한다.
반응형
'🍎 Apple > Combine & Rx' 카테고리의 다른 글
[Combine] timer (by Runloop, Timer Class, DispatchQueue) (2) | 2022.01.13 |
---|---|
[Combine] Operator (4): Sequence Operator (0) | 2022.01.12 |
[Combine] Operator (3): Combining Operator (0) | 2022.01.12 |
[Combine] Operator (2): Filtering Operator (0) | 2022.01.12 |
[RxSwift] Reactive Programming & RxSwift (0) | 2022.01.02 |