cozzin
코찐 기술 블로그
cozzin
전체 방문자
오늘
어제
  • 분류 전체보기
    • Kotlin
    • 백엔드
    • iOS
      • Swift
      • SwiftUI
      • Combine
      • Architecture
    • 개발환경
    • 세미나
    • 생각정리
    • 스터디
    • CS
      • Refactoring
      • OS

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • LinkedIn
  • 강의

공지사항

인기 글

태그

  • Warning
  • SwiftUI
  • 운영체제
  • 워닝제거
  • 테스트
  • Combine
  • CS
  • os
  • WWDC21
  • multicast
  • Swift
  • ios
  • 리팩토링
  • Ribs
  • 컴퓨터공학
  • WWDC
  • darkmode
  • 디자인패턴
  • XCode
  • slide-over

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
cozzin

코찐 기술 블로그

[Combine 책 정리] Chapter 4: Filtering Operators
iOS/Combine

[Combine 책 정리] Chapter 4: Filtering Operators

2021. 1. 13. 14:50
반응형

이전글

  • 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
    'iOS/Combine' 카테고리의 다른 글
    • [Combine 책 정리] Chapter 6: Time Manipulation Operators
    • [Combine 책 정리] Chapter 5: Combining Operators
    • [Combine 책 정리] Chatper 3: Transforming Operators
    • [Combine 책 정리] Chapter 2: Publishers & Subscribers
    cozzin
    cozzin
    Software Engineer

    티스토리툴바