Swift Combine:检查Subject是否有观察者? [英] Swift Combine: Check if Subject has observer?

查看:102
本文介绍了Swift Combine:检查Subject是否有观察者?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在RxSwift中,我们可以使用

In RxSwift we can check if a *Subject has any observer, using hasObserver, how can I do this in Combine on e.g. a PassthroughSubject?

推荐答案

发布问题一段时间后,我编写了这个简单的扩展名.比@Asperi的解决方案简单得多.除了简单性之外,还不确定这两种解决方案之间的优缺点.

Some time after posting my question I wrote this simple extension. Much simpler than @Asperi's solution. Not sure about disadvantages/advantages between the two solutions besides simplicity (of mine).


private enum CounterChange: Int, Equatable {
    case increased = 1
    case decreased = -1
}

extension Publisher {
    func trackNumberOfSubscribers(
        _ notifyChange: @escaping (Int) -> Void
    ) -> AnyPublisher<Output, Failure> {

        var counter = NSNumber.init(value: 0)
        let nsLock = NSLock()

        func updateCounter(_ change: CounterChange, notify: (Int) -> Void) {
            nsLock.lock()
            counter = NSNumber(value: counter.intValue + change.rawValue)
            notify(counter.intValue)
            nsLock.unlock()
        }

        return handleEvents(
            receiveSubscription: { _ in updateCounter(.increased, notify: notifyChange) },
            receiveCompletion: { _ in updateCounter(.decreased, notify: notifyChange) },
            receiveCancel: { updateCounter(.decreased, notify: notifyChange) }
        ).eraseToAnyPublisher()
    }
}

以下是一些测试:

import XCTest
import Combine

final class PublisherTrackNumberOfSubscribersTest: TestCase {

    func test_four_subscribers_complete_by_finish() {
        doTest { publisher in
            publisher.send(completion: .finished)
        }
    }

    func test_four_subscribers_complete_by_error() {
        doTest { publisher in
            publisher.send(completion: .failure(.init()))
        }
    }

}

private extension PublisherTrackNumberOfSubscribersTest {
    struct EmptyError: Swift.Error {}
    func doTest(_ line: UInt = #line, complete: (PassthroughSubject<Int, EmptyError>) -> Void) {
        let publisher = PassthroughSubject<Int, EmptyError>()

        var numberOfSubscriptions = [Int]()
        let trackable = publisher.trackNumberOfSubscribers { counter in
            numberOfSubscriptions.append(counter)
        }

        func subscribe() -> Cancellable {
            return trackable.sink(receiveCompletion: { _ in }, receiveValue: { _ in })
        }

        let cancellable1 = subscribe()
        let cancellable2 = subscribe()
        let cancellable3 = subscribe()
        let cancellable4 = subscribe()

        XCTAssertNotNil(cancellable1, line: line)
        XCTAssertNotNil(cancellable2, line: line)
        XCTAssertNotNil(cancellable3, line: line)
        XCTAssertNotNil(cancellable4, line: line)

        cancellable1.cancel()
        cancellable2.cancel()

        complete(publisher)
        XCTAssertEqual(numberOfSubscriptions, [1, 2, 3, 4, 3, 2, 1, 0], line: line)
    }
}

这篇关于Swift Combine:检查Subject是否有观察者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆