Skip to content

Commit e0d8235

Browse files
committed
🆕 Add a 'collect(until:)' operator
1 parent 9c00a52 commit e0d8235

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//
2+
// CollectUntilTrigger.swift
3+
// CombineExt
4+
//
5+
// Created by ferologics on 09/06/2021.
6+
// Copyright © 2021 Combine Community. All rights reserved.
7+
//
8+
9+
#if canImport(Combine)
10+
import Combine
11+
12+
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
13+
public extension Publisher {
14+
func collect<CollectionTrigger>(
15+
until trigger: CollectionTrigger
16+
) -> AnyPublisher<[Output], Failure> where
17+
CollectionTrigger: Publisher,
18+
CollectionTrigger.Output == Void,
19+
CollectionTrigger.Failure == Never {
20+
var events = [Output]()
21+
22+
let eventPublisher = PassthroughSubject<[Output], Failure>()
23+
var cancellables = [AnyCancellable]()
24+
25+
self.sink { completion in
26+
eventPublisher.send(completion: completion)
27+
} receiveValue: { output in
28+
events.append(output)
29+
}
30+
.store(in: &cancellables)
31+
32+
trigger.sink { _ in
33+
eventPublisher.send(events)
34+
events = []
35+
}
36+
.store(in: &cancellables)
37+
38+
func cleanUp() {
39+
cancellables.forEach { $0.cancel() }
40+
cancellables = []
41+
}
42+
43+
return eventPublisher
44+
.handleEvents(
45+
receiveCompletion: { _ in cleanUp() },
46+
receiveCancel: { cleanUp() }
47+
)
48+
.eraseToAnyPublisher()
49+
}
50+
}
51+
#endif

Tests/CollectUntilTriggerTests.swift

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// CollectUntilTriggerTests.swift
3+
// CombineExtTests
4+
//
5+
// Created by ferologics on 09/06/2021.
6+
//
7+
8+
#if !os(watchOS)
9+
import XCTest
10+
import Combine
11+
12+
@available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
13+
class CollectUntilTriggerTests: XCTestCase {
14+
var subscription: AnyCancellable!
15+
16+
func test() {
17+
// Given
18+
let elements = [1,2,3,4,5]
19+
var receivedElements = [Int]()
20+
let elementsPublisher = PassthroughSubject<Int, Never>()
21+
let trigger = PassthroughSubject<Void, Never>()
22+
23+
// When
24+
subscription = elementsPublisher
25+
.collect(until: trigger)
26+
.sink { receivedElements = $0 }
27+
28+
for x in elements {
29+
elementsPublisher.send(x)
30+
}
31+
32+
// Then
33+
XCTAssertTrue(receivedElements.isEmpty)
34+
trigger.send(())
35+
XCTAssertEqual(elements.count, receivedElements.count)
36+
for (a, b) in zip(elements, receivedElements) {
37+
XCTAssertEqual(a, b)
38+
}
39+
}
40+
}
41+
#endif

0 commit comments

Comments
 (0)