Skip to content

Instantly share code, notes, and snippets.

@noahsark769
Created November 29, 2019 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noahsark769/ac19951992fb27a54a99c5aa36c823a3 to your computer and use it in GitHub Desktop.
Save noahsark769/ac19951992fb27a54a99c5aa36c823a3 to your computer and use it in GitHub Desktop.
CombineLatestCollection crash
import XCTest
import Combine
extension Collection where Element: Publisher {
/// Combine the array of publishers to give a single publisher of an array
/// of their outputs.
public func combineLatest() -> CombineLatestCollection<Self> {
return CombineLatestCollection(self)
}
}
/// A `Publisher` that combines an array of publishers to provide an output of
/// an array of their respective outputs.
///
/// Changes will be sent if any of the publishers' values changes.
///
/// When any publisher fails, that will cause the failure of this publisher.
///
/// When all publishers complete successfully, that will cause the successful
/// completion of this publisher.
public struct CombineLatestCollection<Publishers>: Publisher
where
Publishers: Collection,
Publishers.Element: Publisher
{
public typealias Output = [Publishers.Element.Output]
public typealias Failure = Publishers.Element.Failure
private let publishers: Publishers
public init(_ publishers: Publishers) {
self.publishers = publishers
}
public func receive<Subscriber>(subscriber: Subscriber)
where
Subscriber: Combine.Subscriber,
Subscriber.Failure == Failure,
Subscriber.Input == Output
{
let subscription = Subscription(subscriber: subscriber,
publishers: publishers)
subscriber.receive(subscription: subscription)
}
}
extension CombineLatestCollection {
/// A subscription for a CombineLatestCollection publisher.
public final class Subscription<Subscriber>: Combine.Subscription
where
Subscriber: Combine.Subscriber,
Subscriber.Failure == Publishers.Element.Failure,
Subscriber.Input == Output
{
private let subscribers: [AnyCancellable]
fileprivate init(subscriber: Subscriber, publishers: Publishers) {
var values: [Publishers.Element.Output?] = Array(repeating: nil, count: publishers.count)
var completions = 0
var hasCompleted = false
let lock = NSLock()
subscribers = publishers.enumerated().map { index, publisher in
publisher
.sink(receiveCompletion: { completion in
lock.lock()
defer { lock.unlock() }
guard case .finished = completion else {
// One failure in any of the publishers cause a
// failure for this subscription.
subscriber.receive(completion: completion)
hasCompleted = true
return
}
completions += 1
if completions == publishers.count {
subscriber.receive(completion: completion)
hasCompleted = true
}
}, receiveValue: { value in
lock.lock()
defer { lock.unlock() }
guard !hasCompleted else { return }
values[index] = value
// Get non-optional array of values and make sure we
// have a full array of values.
let current = values.compactMap { $0 }
if current.count == publishers.count {
_ = subscriber.receive(current)
}
})
}
}
public func request(_ demand: Subscribers.Demand) {}
public func cancel() {
subscribers.forEach { $0.cancel() }
}
}
}
class CombineLatestCollectionTest: XCTestCase {
func testForwardingSubscription() {
let subject1 = CurrentValueSubject<String, Never>("One")
let subject2 = CurrentValueSubject<String, Never>("Two")
let passthrough = PassthroughSubject<[String], Never>()
var values: [[String]] = []
let passthroughCancellable = passthrough.sink { value in
values.append(value)
}
let cancellable = [subject1.eraseToAnyPublisher(), subject2.eraseToAnyPublisher()].combineLatest().subscribe(passthrough)
XCTAssertEqual(try XCTUnwrap(values.last), ["One", "Two"])
cancellable.cancel()
passthroughCancellable.cancel()
}
}
@Bharath1232
Copy link

Bharath1232 commented Mar 9, 2021

Working fine in iOS 14.....
crash in iOS 13.4.1

@Bharath1232
Copy link

is this the updated the code for that crash

@Bharath1232
Copy link

Fatal error: Invalid state: Received value before receiving subscription: file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/PubSub/PubSub-134.102/Combine/Source/FilterProducer.swift, line 99

2021-03-09 10:54:13.964803+0530 BankEzy[16430:2821894] Fatal error: Invalid state: Received value before receiving subscription: file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/PubSub/PubSub-134.102/Combine/Source/FilterProducer.swift, line 99

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment