upstream 에서 값을 방출할 때마다 잠시 동안 지연시켜 다음 지정한 스케줄러에서 방출합니다.delay(for:tolerance:scheduler:options)
import Combine
import SwiftUI
import PlaygroundSupport
// 1
let valuesPerSecond = 1.0
let delayInSeconds = 1.5
// 2
let sourcePublisher = PassthroughSubject<Date, Never>()
// 3
let delayedPublisher = sourcePublisher.delay(for: .seconds(delayInSeconds),
scheduler: DispatchQueue.main)
// 4
let subscription = Timer
.publish(every: 1.0 / valuesPerSecond,
on: .main,
in: .common)
.autoconnect()
.subscribe(sourcePublisher)
// 5
let sourceTimeline = TimelineView(title: "Emitted values (\(valuesPerSecond) per sec.):")
// 6
let delayedTimeline = TimelineView(title: "Delayed values (with a \(delayInSeconds)s delay):")
let view = VStack(spacing: 50) {
sourceTimeline
delayedTimeline
}
// 7
PlaygroundPage.current.liveView = UIHostingController(rootView: view.frame(width: 375, height: 600))
sourcePublisher.displayEvents(in: sourceTimeline)
delayedPublisher.displayEvents(in: delayedTimeline)
1. 매 1초마다 값을 방출하는 publisher를 만들고, 1.5초 후 방출하는 걸 만들고 비교 2. 날짜를 받는 Subject를 만들고 3. delay 연산자를 이용해 sourcePublisher를 1.5초 지연시킵니다. 4. 초당 1개의 값을 방출하는 타이머를 만들고, autoconnect()로 바로 시작, 구독을 합니다. 5 ~ 7. 대충 View 만들기
Collecting values
collect()
지정된 시간마다 값을 방출합니다.
import Combine
import SwiftUI
import PlaygroundSupport
let valuesPerSecond = 1.0
let collectTimeStride = 4
let sourcePublisher = PassthroughSubject<Date, Never>()
let collectedPublisher = sourcePublisher
.collect(.byTime(DispatchQueue.main, .seconds(collectTimeStride)))
let subscription = Timer
.publish(every: 1.0 / valuesPerSecond, on: .main, in: .common)
.autoconnect()
.subscribe(sourcePublisher)
let sourceTimeline = TimelineView(title: "Emitted values:")
let collectedTimeline = TimelineView(title: "Collected values (every \(collectTimeStride)s):")
let view = VStack(spacing: 40) {
sourceTimeline
collectedTimeline
}
PlaygroundPage.current.liveView = UIHostingController(rootView: view.frame(width: 375, height: 600))
sourcePublisher.displayEvents(in: sourceTimeline)
collectedPublisher.displayEvents(in: collectedTimeline)
1. 4초마다 값을 구독하기 위해 collect() 연산자를 사용합니다.
+ 추가로 flatMap을 이용해서 방출됐던 값들을 마지막 4초마다 보여줄 수 있습니다.
let collectedPublisher = sourcePublisher
.collect(.byTime(DispatchQueue.main, .seconds(collectTimeStride)))
.flatMap { dates in dates.publisher } // +추가
Collecting values(2)
collect(_:options:)
최대치로 설정해둔 갯수만 collect 합니다. collect(_:options:)
import Combine
import SwiftUI
import PlaygroundSupport
let valuesPerSecond = 1.0
let collectTimeStride = 4
// 추가
let collectMaxCount = 2
let sourcePublisher = PassthroughSubject<Date, Never>()
let collectedPublisher = sourcePublisher
.collect(.byTime(DispatchQueue.main,
.seconds(collectTimeStride)))
.flatMap { dates in dates.publisher }
// 추가
let collectedPublisher2 = sourcePublisher
.collect(.byTimeOrCount(DispatchQueue.main,
.seconds(collectTimeStride),
collectMaxCount)) // 최대치 설정
.flatMap { dates in dates.publisher}
let subscription = Timer
.publish(every: 1.0 / valuesPerSecond, on: .main, in: .common)
.autoconnect()
.subscribe(sourcePublisher)
let sourceTimeline = TimelineView(title: "Emitted values:")
let collectedTimeline = TimelineView(title: "Collected values (every \(collectTimeStride)s):")
// 추가
let collectedTimeline2 = TimelineView(title: "Collected values (at most \(collectMaxCount) every \(collectTimeStride)s):")
let view = VStack(spacing: 40) {
sourceTimeline
collectedTimeline
// 추가
collectedTimeline2
}
PlaygroundPage.current.liveView = UIHostingController(rootView: view.frame(width: 375, height: 600))
sourcePublisher.displayEvents(in: sourceTimeline)
collectedPublisher.displayEvents(in: collectedTimeline)
// 추가
collectedPublisher2.displayEvents(in: collectedTimeline2)
최대치로 설정해둔 2개의 값만 collect 합니다.
Holding off on events
debounce(for:scheduler:)
subject에서 방출되는 값중 , for에 지정된 시간동안 입력되었던 '마지막' 값들을 한꺼번에 방출합니다. debounce(for:scheduler:)
import Combine
import SwiftUI
import PlaygroundSupport
let subject = PassthroughSubject<String, Never>()
// 1
let debounced = subject
.debounce(for: .seconds(1.0), scheduler: DispatchQueue.main)
// 2
.share()
let subjectTimeline = TimelineView(title: "Emitted values")
let debouncedTimeline = TimelineView(title: "Debounced values")
let view = VStack(spacing: 100) {
subjectTimeline
debouncedTimeline
}
PlaygroundPage.current.liveView = UIHostingController(rootView: view.frame(width: 375, height: 600))
subject.displayEvents(in: subjectTimeline)
debounced.displayEvents(in: debouncedTimeline)
let subscription1 = subject
.sink { string in
print("+\(deltaTime)s: Subject emitted: \(string)")
}
let subscription2 = debounced
.sink { string in
print("+\(deltaTime)s: Debounced emitted: \(string)")
}
subject.feed(with: typingHelloWorld)
1. debounce를 사용해서 for에 지정된 시간동안 입력됐던 값들을 방출합니다. 2. 여러 번 subscribe할때 동일한 결과값을 보장하기 위해 share()를 사용합니다.
Throttle(for:scheduler:latest:)
subject에 방출되었던 값중, for에 지정된 시간동안 입력된 가장 '첫번째' 또는 '최근(latest)' 값을 방출합니다. Throttle(for:scheduler:latest:) 첫번째 값 방출시 (latest: false)
import Combine
import SwiftUI
import PlaygroundSupport
let throttleDelay = 1.0
let subject = PassthroughSubject<String, Never>()
let throttled = subject
.throttle(for: .seconds(throttleDelay),
scheduler: DispatchQueue.main,
latest: false)
.share()
let subjectTimeline = TimelineView(title: "Emitted values")
let throttledTimeline = TimelineView(title: "Throttled values")
let view = VStack(spacing: 100) {
subjectTimeline
throttledTimeline
}
PlaygroundPage.current.liveView = UIHostingController(rootView: view.frame(width: 375, height: 600))
subject.displayEvents(in: subjectTimeline)
throttled.displayEvents(in: throttledTimeline)
let subscription1 = subject
.sink { string in
print("+\(deltaTime)s: Subject emitted: \(string)")
}
let subscription2 = throttled
.sink { string in
print("+\(deltaTime)s: Throttled emitted: \(string)")
}
subject.feed(with: typingHelloWorld)