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

블로그 메뉴

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

공지사항

인기 글

태그

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

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
cozzin

코찐 기술 블로그

[Combine 책 정리] Chapter 6: Time Manipulation Operators
iOS/Combine

[Combine 책 정리] Chapter 6: Time Manipulation Operators

2021. 1. 19. 22:41
반응형

안녕하세요 코찐입니다.

이번 챕터는 Time manipulation(시간 조작)에 관한 챕터입니다.

 

아래의 자료를 따라서 공부하고 있습니다.

하나하나 따라하기 좋게 구성되어 있습니다.

 

https://www.raywenderlich.com/books/combine-asynchronous-programming-with-swift/v2.0

https://github.com/raywenderlich/comb-materials/tree/editions/2.0/06-time-based-operators/projects

 

raywenderlich/comb-materials

The projects and the materials that accompany the Combine: Asynchronous Programming with Swift Book - raywenderlich/comb-materials

github.com

 

플레이그라운드를 열어보면 직관적인 실습을 위해서 많은 준비를 해둔 것을 알 수 있습니다. (진짜 존경스러움...)

Shifting time

이번엔 SwiftUI 도 import 되어있습니다... 역동적인걸 보여주려고 하나봅니다

 

더보기

(이렇게 차근차근 설명해 나가는걸 Swift 기초 강의에도 적용해도 좋을 것 같다. 스스로 이해하는 속도에 맞춰서 따라갈 수 있는 듯)

 

let sourcePublisher = PassthroughSubject<Date, Never>()
let delayedPublisher = sourcePublisher.delay(for: .seconds(delayInSeconds), scheduler: DispatchQueue.main)

let subscription = Timer
    .publish(every: 1.0 / valuesPerSecond, on: .main, in: .common)
    .autoconnect() // value emit 전에 connect해야하는데, autoconnect라서 첫번째 subscirption에 connect
    .subscribe(sourcePublisher)

 

1초마다 value를 생산하고, 1.5초 delay 한다.

동적으로 보면 이렇게 생겼다.

 

 

Collecting values

  • 특정 기간 동안의 value를 모아줌
  • ex) 특정 기간 동안의 평균을 구할 때 사용
let valuesPerSecond = 1.0
let collectTimeStride = 4

let sourcePublisher = PassthroughSubject<Date, Never>()
let collectedPublisher = sourcePublisher
    .collect(.byTime(DispatchQueue.main, .seconds(collectTimeStride)))
    .flatMap { dates in dates.publisher }

let subscription = Timer
    .publish(every: 1.0 / valuesPerSecond, on: .main, in: .common)
    .autoconnect()
    .subscribe(sourcePublisher)

 

collect된 value들이 모여서 array로 만들어지는 것을 볼 수 있다.

 

 

그리고 여기에 예제 하나를 더 추가한다.

이번엔 limit로 maxCount를 넣어본다

 

let collectMaxCount = 2

let collectedPublisher2 = sourcePublisher
    .collect(.byTimeOrCount(DispatchQueue.main, .seconds(collectTimeStride), collectMaxCount))
    .flatMap { dates in dates.publisher }

 

비슷하게 해서 View를 연결하면 최대치로 설정해둔 2개만 collect되는 것을 볼 수 있다.

 

 

Holding off on events

  • TextField에 타이핑 다 했을 때 다음 동작을 수행하고 싶을 때가 있음
  • debounce, throttle: 이 두개가 맨날 헷갈리는데 잘 정리해보자. 
  • debounce: 입력 주기가 끝나면 출력
  • throttle: 특정 주기안의 첫번째 or 마지막 value 출력

https://pks2974.medium.com/throttle-%EC%99%80-debounce-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC%ED%95%98%EA%B8%B0-2335a9c426ff

 

Throttle 와 Debounce 개념 정리하기

Throttle 와 Debounce 라는 개념 을 알게 되어 이를 정리해보고자 한다.

pks2974.medium.com

 

이 포스팅에서 잘 정리해주고 있으니, 필요하면 한 번 살펴보자.

 

debounce

  • 입력 주기가 끝나면 마지막 값 출력
  • 추가로 value가 들어오면 주기가 다시 갱신됨
let subject = PassthroughSubject<String, Never>()

let debounced = subject
    .debounce(for: .seconds(1.0), scheduler: DispatchQueue.main)
    .share() // 여러 subscriber가 동일한 result를 받기 위함

 

 

throttle

let throttleDelay = 1.0

let subject = PassthroughSubject<String, Never>()

let throttled = subject
    .throttle(for: .seconds(throttleDelay), scheduler: DispatchQueue.main, latest: false)
    .share()

 

  • 처음에 구독한 시점에 value를 한번 바로 방출
  • latest: false로 주면 특정 주기 안의 첫번째 value 출력
  • 주기를 1초 간격으로 설정함
  • 버튼 터치를 여러번 할 수 있는 경우에 사용하면 좋을 듯

 

 

이번에는 latest: true로 옵션을 설정해보자

그러면 특정 주기안의 마지막 value를 출력!

 

 

Timing out

특정 시간안에 이벤트가 없으면 종료

let subject = PassthroughSubject<Void, Never>()

let timedOutSubject = subject.timeout(.seconds(5), scheduler: DispatchQueue.main)

 

timeout 발생하면 finish 대신에 error를 던지는 경우가 더 흔한 케이스

enum TimeoutError: Error {
    case timedOut
}

let subject = PassthroughSubject<Void, TimeoutError>()

let timedOutSubject = subject.timeout(
    .seconds(5),
    scheduler: DispatchQueue.main,
    customError: { .timedOut })

 

 

Measuring time

value 사이의 시간을 계산하고 싶을 때 사용

  • DispatchQueue를 사용할 경우:  나노초 단위 DispatchTimeInterval 로 리턴됨
  • Runloop를 사용할 경우: 초단위로 리턴됨

 

 

let subject = PassthroughSubject<String, Never>()

let measureSubject = subject.measureInterval(using: DispatchQueue.main)

let subjectTimeline = TimelineView(title: "Emitted values")
let measureTimeline = TimelineView(title: "Measured values")

// ...중략...

let subscription1 = subject.sink {
    print("+\(deltaTime)s: Subject emitted: \($0)")
}

let subscription2 = measureSubject.sink {
    print("+\(deltaTime)s: Measure emitted: \(Double($0.magnitude) / 1_000_000_000.0)")
}

 

 

 

이번 챕터는 여기까지 입니다.

다음 챕터에서 만나요!

반응형
저작자표시 (새창열림)

'iOS > Combine' 카테고리의 다른 글

[Combine 책 정리] Chapter 9: Networking  (0) 2021.01.27
[Combine 책 정리] Chapter 7: Sequence Operators  (0) 2021.01.22
[Combine 책 정리] Chapter 5: Combining Operators  (0) 2021.01.18
[Combine 책 정리] Chapter 4: Filtering Operators  (0) 2021.01.13
[Combine 책 정리] Chatper 3: Transforming Operators  (0) 2021.01.12
    'iOS/Combine' 카테고리의 다른 글
    • [Combine 책 정리] Chapter 9: Networking
    • [Combine 책 정리] Chapter 7: Sequence Operators
    • [Combine 책 정리] Chapter 5: Combining Operators
    • [Combine 책 정리] Chapter 4: Filtering Operators
    cozzin
    cozzin
    Software Engineer

    티스토리툴바