티스토리 뷰
728x90
오늘은 이어서 Combining 연산자에 대해 공부해 보겠습니다.
Prepending
upstream에서 방출한 값 앞에 추가해서 보내는 용도로 사용합니다.
prepend(Output)
publisher에서 방출 되는 이벤트 이전에 값을 넣어줄 때 사용합니다.
var subscriptions = Set<AnyCancellable>() example(of: "prepend(output)") { let publisher = [3, 4].publisher publisher .prepend(1, 2) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) } /* ——— Example of: prepend(output) ——— 1 2 3 4 */
아래처럼 음수 를 추가해도 순서대로 나열 됩니다.var subscriptions = Set<AnyCancellable>() example(of: "prepend(output)") { let publisher = [3, 4].publisher publisher .prepend(1, 2) .prepend(-1, -2) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) } /* ——— Example of: prepend(output) ——— -1 -2 1 2 3 4 */
prepend(Sequence)
(Output)과 유사하며, Sequence를 준수합니다.
var subscriptions = Set<AnyCancellable>() example(of: "prepend(Sequence)") { let publisher = [5, 6, 7].publisher publisher .prepend([3, 4]) .prepend(stride(from: 6, to: 11, by: 2)) .prepend(Set(1...2)) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) } /* ——— Example of: prepend(Sequence) ——— 2 또는 1 1 또는 2 6 8 10 3 4 5 6 7 */
* Set은 정렬되지 않기 때문에 순서가 랜덤으로 나옵니다.prepend(Publisher)
두개의 다른 publisher들을 하나로 합쳐서 나열할 경우에 사용합니다.
(publisher2가 오리지날 publisher 이전에 방출됩니다.)
// #1 var subscriptions = Set<AnyCancellable>() example(of: "prepend(Publisher)") { let publisher1 = [3, 4].publisher let publisher2 = [1, 2].publisher publisher1 .prepend(publisher2) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) } /* ——— Example of: prepend(Publisher) ——— // publisher2 1 2 // publisher1 3 4 */ // #2 var subscriptions = Set<AnyCancellable>() example(of: "prepend(Publisher) #2") { let publisher1 = [3, 4].publisher let publisher2 = PassthroughSubject<Int, Never>() publisher1 .prepend(publisher2) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) publisher2.send(1) publisher2.send(2) publisher2.send(completion: .finished) } /* ——— Example of: prepend(Publisher) #2 ——— 1 2 3 4 */
* publihser2 값 방출이 끝났다는걸 알려주려면 complete 시켜줘야 합니다.
안해주면 publisher1 값만 나오게 됩니다.
Appending
append(Output)
prepend와 반대의 개념으로 생각하면 됩니다.
prepend가 이벤트를 방출할때 upstream 앞에 붙였다면,
append는 뒤에 붙입니다.
// #1 var subscriptions = Set<AnyCancellable>() example(of: "append(Output)") { let publisher = [1].publisher publisher .append(2, 3) .append(4) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) } /* ——— Example of: append(Output) ——— 1 2 3 4 */ // #2 var subscriptions = Set<AnyCancellable>() example(of: "append(Output)") { let publisher = PassthroughSubject<Int, Never>() publisher .append(3, 4) .append(5) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) publisher.send(1) publisher.send(2) publisher.send(completion: .finished) // <- 추가 해줘야 append operator가 동작합니다. } /* ——— Example of: append(Output) ——— 1 2 3 4 5 */
append(Sequence)
var subscriptions = Set<AnyCancellable>() example(of: "append(Sequence)") { let publisher = [1, 2, 3].publisher publisher .append([4, 5]) .append(Set([6, 7])) .append(stride(from: 8, to: 11, by: 2)) // 8부터 11까지 2씩 증가 .sink(receiveValue: { print($0) }) .store(in: &subscriptions) } /* ——— Example of: append(Sequence) ——— 1 2 3 4 5 6 또는 7 7 또는 6 8 10 */
append(Publisher)
var subscriptions = Set<AnyCancellable>() example(of: "append(Publisher)") { let publisher1 = [1, 2].publisher let publisher2 = [3, 4].publisher publisher1 .append(publisher2) .sink(receiveValue: { print($0) }) .store(in: &subscriptions) } /* ——— Example of: append(Publisher) ——— 1 2 3 4 */
Advanced combining
switchToLatest()
새로운 구독이 들어오면 이전 publisher를 무시하고, 최신 publisher로 전환 할 수 있습니다.
var subscriptions = Set<AnyCancellable>() example(of: "switchToLatest") { let publisher1 = PassthroughSubject<Int, Never>() let publisher2 = PassthroughSubject<Int, Never>() let publisher3 = PassthroughSubject<Int, Never>() let publishers = PassthroughSubject<PassthroughSubject<Int, Never>, Never>() publishers .switchToLatest() // 최신 publisher로 switch .sink(receiveCompletion: { _ in print("Completed!")}, receiveValue: { print($0) } ) .store(in: &subscriptions) publishers.send(publisher1) publisher1.send(1) publisher1.send(2) publishers.send(publisher2) // publisher2를 구독하므로 publisher1.send(3) // publisher1의 해당 이벤트는 무시됨 publisher2.send(4) publisher2.send(5) publishers.send(publisher3) // publisher3를 구독하므로 publisher2.send(6) // publisher2의 해당 이벤트는 무시됨 publisher3.send(7) publisher3.send(8) publisher3.send(9) publisher3.send(completion: .finished) publishers.send(completion: .finished) } /* ——— Example of: switchToLatest ——— 1 2 4 5 7 8 9 Completed! */
아래는 네트워크 요청을 하는 버튼을 누른후 바로 또 네트워크 요청을 하게 되는 경우 어떻게 처리되는지 보여주는 예시 입니다.
var subscriptions = Set<AnyCancellable>() example(of: "switchToLatest - Network Request") { let url = URL(string: "https://source.unsplash.com/random")! func getImage() -> AnyPublisher<UIImage?, Never> { URLSession.shared .dataTaskPublisher(for: url) .map { data, _ in UIImage(data: data) } .print("image") .replaceError(with: nil) .eraseToAnyPublisher() } let taps = PassthroughSubject<Void, Never>() taps .map { _ in getImage() } .switchToLatest() .sink(receiveValue: { _ in }) .store(in: &subscriptions) taps.send() // 랜덤사진 받아오는 URL 호출 DispatchQueue.main.asyncAfter(deadline: .now() + 3) { taps.send() // 3초후 URL 호출 } DispatchQueue.main.asyncAfter(deadline: .now() + 3.1) { taps.send() // 3.1초후 URL 호출 (이전 URL 호출 취소) } } /* ——— Example of: switchToLatest - Network Request ——— image: receive subscription: (DataTaskPublisher) image: request unlimited image: receive value: (Optional(<UIImage:0x6000009dc630 anonymous {1080, 720} renderingMode=automatic(original)>)) image: receive finished image: receive subscription: (DataTaskPublisher) image: request unlimited image: receive cancel <--- 여기서 취소 image: receive subscription: (DataTaskPublisher) image: request unlimited image: receive value: (Optional(<UIImage:0x6000009d2fd0 anonymous {1080, 1350} renderingMode=automatic(original)>)) image: receive finished */
+추가
unsplash 의 랜덤사진을 가져오는 URL이기 때문에 아래 빨간표시를 클릭해서 사진 확인도 할 수 있습니다.
사진에 우클릭 후 Value History를 누르면 이전값도 확인할 수 있습니다.
merge(with:)
다른 publisher를 합치는 연산자 입니다.
var subscriptions = Set<AnyCancellable>() example(of: "merge(with:)") { let publisher1 = PassthroughSubject<Int, Never>() let publisher2 = PassthroughSubject<Int, Never>() publisher1 .merge(with: publisher2) .sink(receiveCompletion: { _ in print("Completed")}, receiveValue: { print($0) }) .store(in: &subscriptions) publisher1.send(1) publisher1.send(2) publisher2.send(3) publisher1.send(4) publisher2.send(5) publisher1.send(completion: .finished) publisher2.send(completion: .finished) } /* ——— Example of: merge(with:) ——— 1 2 3 4 5 Completed */
combineLatest
publisher들의 최신 값들을 합쳐 튜플값으로 방출합니다.
*아래 예시 코드보단 그림이 좀더 이해가 잘갑니다.
var subscriptions = Set<AnyCancellable>() example(of: "combineLatest") { let publisher1 = PassthroughSubject<Int, Never>() let publisher2 = PassthroughSubject<String, Never>() publisher1 .combineLatest(publisher2) .sink(receiveCompletion: { _ in print("Completed")}, receiveValue: { print("P1: \($0), P2: \($1)") }) .store(in: &subscriptions) publisher1.send(1) // 생략 publisher1.send(2) publisher2.send("a") // P1: 2 와 합쳐짐 publisher2.send("b") // P1: 2 와 합쳐짐, P1: 3과 합쳐짐 publisher1.send(3) publisher2.send("c") // P1: 3 과 합쳐짐 publisher1.send(completion: .finished) publisher2.send(completion: .finished) } /* ——— Example of: combineLatest ——— P1: 2, P2: a P1: 2, P2: b P1: 3, P2: b P1: 3, P2: c Completed */
zip
두개의 publisher에서 방출되는 값들을 짝지어 하나로 합쳐주는 역할을 합니다.
* 각 이벤트의 요소들 갯수가 일치하는만큼만 묶어 내려줍니다.
var subscriptions = Set<AnyCancellable>() example(of: "zip") { let publisher1 = PassthroughSubject<Int, Never>() let publisher2 = PassthroughSubject<String, Never>() publisher1 .zip(publisher2) .sink( receiveCompletion: { _ in print("Completed") }, receiveValue: { print("P1: \($0), P2: \($1)") } ) .store(in: &subscriptions) publisher1.send(1) publisher1.send(2) publisher2.send("a") // (1, "a") publisher2.send("b") // (2, "b") publisher1.send(3) publisher2.send("c") // (3, "c") publisher2.send("d") // 짝이 없으므로 Pass ~ publisher1.send(completion: .finished) publisher2.send(completion: .finished) } /* ——— Example of: zip ——— P1: 1, P2: a P1: 2, P2: b P1: 3, P2: c Completed */
728x90
'iOS' 카테고리의 다른 글
[Combine] Chapter6 : Time Manipulation Operators (0) | 2022.11.24 |
---|---|
[Swift 알고리즘] - 문자열 내림차순으로 배치하기 (Programmers) (0) | 2022.11.15 |
[Swift 알고리즘] - 자연수 뒤집어 배열로 만들기 (Programmers) (0) | 2022.11.05 |
[Combine] Chapter4: Filtering Operators (1) | 2022.11.03 |
[Combine] Chapter 3: Transforming Operators (0) | 2022.10.28 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- Swift joined
- swift reduce
- 2023년 회고
- Swift 알고리즘
- Swift Leetcode
- Swift inout
- Swift 프로퍼티
- swift (programmers)
- iOS error
- Swift joined()
- Class
- Swift final
- Swift 프로그래머스
- swift 고차함수
- swift programmers
- Swift init
- RTCCameraVideoCapturer
- CS 네트워크
- Swift
- Swift Error Handling
- swift protocol
- 원티드 프리온보딩
- RIBs tutorial
- ios
- Combine: Asynchronous Programming with Swift
- removeLast()
- Swift RIBs
- Swift ModernRIBs
- Swift 내림차순
- swift property
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함