Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 快速联合收割机:检查受试者是否有观察员?_Swift_Rx Swift_Combine - Fatal编程技术网

Swift 快速联合收割机:检查受试者是否有观察员?

Swift 快速联合收割机:检查受试者是否有观察员?,swift,rx-swift,combine,Swift,Rx Swift,Combine,在RxSwift中,我们可以检查*主题是否有任何观察者,使用,我如何在Combine中对例如PassthroughSubject这样的对象执行此操作?没有人需要此功能。。。苹果并没有通过API提供这种功能,事实上,我也不推荐这样做,因为这就像在代码中手动检查pre-ARC Objective-C中的retainCount值,以获得某种决策 无论如何,这是可能的。让我们把它当作一个实验室练习。希望有人觉得这有帮助 免责声明:下面的代码并没有经过所有发布者的测试,对于一些真实世界的项目来说也不安全。

在RxSwift中,我们可以检查*主题是否有任何观察者,使用,我如何在Combine中对例如PassthroughSubject这样的对象执行此操作?

没有人需要此功能。。。苹果并没有通过API提供这种功能,事实上,我也不推荐这样做,因为这就像在代码中手动检查pre-ARC Objective-C中的retainCount值,以获得某种决策

无论如何,这是可能的。让我们把它当作一个实验室练习。希望有人觉得这有帮助

免责声明:下面的代码并没有经过所有发布者的测试,对于一些真实世界的项目来说也不安全。这只是一个演示

所以,因为有很多种出版商,它们都是最终的和私有的,而且可能有通过类型橡皮擦来的,所以我们需要通用的东西应用于任何出版商,因此操作员

extension Publisher {
    public func countingSubscribers(_ callback: ((Int) -> Void)? = nil)
        -> Publishers.SubscribersCounter<Self> {
            return Publishers.SubscribersCounter<Self>(upstream: self, callback: callback)
    }
}
<P>2,当它在链的中间某个地方,然后接收关于更改的订户计数< /P>的回调。
let publisher = URLSession.shared
        .dataTaskPublisher(for: URL(string: "https://www.google.com")!)
        .countingSubscribers({ count in print("Observers: \(count)") })
        .receive(on: DispatchQueue.main)
        .map { _ in "Data received" }
        .replaceError(with: "An error occurred")
以下是实施:

import Combine

extension Publishers {

    public class SubscribersCounter<Upstream> : Publisher where Upstream : Publisher {

        private(set) var numberOfSubscribers = 0

        public typealias Output = Upstream.Output
        public typealias Failure = Upstream.Failure

        public let upstream: Upstream
        public let callback: ((Int) -> Void)?

        public init(upstream: Upstream, callback: ((Int) -> Void)?) {
            self.upstream = upstream
            self.callback = callback
        }

        public func receive<S>(subscriber: S) where S : Subscriber,
            Upstream.Failure == S.Failure, Upstream.Output == S.Input {
                self.increase()
                upstream.receive(subscriber: SubscribersCounterSubscriber<S>(counter: self, subscriber: subscriber))
        }

        fileprivate func increase() {
            numberOfSubscribers += 1
            self.callback?(numberOfSubscribers)
        }

        fileprivate func decrease() {
            numberOfSubscribers -= 1
            self.callback?(numberOfSubscribers)
        }

        // own subscriber is needed to intercept upstream/downstream events
        private class SubscribersCounterSubscriber<S> : Subscriber where S: Subscriber {
            let counter: SubscribersCounter<Upstream>
            let subscriber: S

            init (counter: SubscribersCounter<Upstream>, subscriber: S) {
                self.counter = counter
                self.subscriber = subscriber
            }

            deinit {
                Swift.print(">> Subscriber deinit")
            }

            func receive(subscription: Subscription) {
                subscriber.receive(subscription: SubscribersCounterSubscription<Upstream>(counter: counter, subscription: subscription))
            }

            func receive(_ input: S.Input) -> Subscribers.Demand {
                return subscriber.receive(input)
            }

            func receive(completion: Subscribers.Completion<S.Failure>) {
                subscriber.receive(completion: completion)
            }

            typealias Input = S.Input
            typealias Failure = S.Failure
        }

        // own subcription is needed to handle cancel and decrease
        private class SubscribersCounterSubscription<Upstream>: Subscription where Upstream: Publisher {
            let counter: SubscribersCounter<Upstream>
            let wrapped: Subscription

            private var cancelled = false
            init(counter: SubscribersCounter<Upstream>, subscription: Subscription) {
                self.counter = counter
                self.wrapped = subscription
            }

            deinit {
                Swift.print(">> Subscription deinit")
                if !cancelled {
                    counter.decrease()
                }
            }

            func request(_ demand: Subscribers.Demand) {
                wrapped.request(demand)
            }

            func cancel() {
                wrapped.cancel()
                if !cancelled {
                    cancelled = true
                    counter.decrease()
                }
            }
        }
    }
}

没有人需要这个。。。苹果并没有通过API提供这种功能,事实上,我也不推荐这样做,因为这就像在代码中手动检查pre-ARC Objective-C中的retainCount值,以获得某种决策

无论如何,这是可能的。让我们把它当作一个实验室练习。希望有人觉得这有帮助

免责声明:下面的代码并没有经过所有发布者的测试,对于一些真实世界的项目来说也不安全。这只是一个演示

所以,因为有很多种出版商,它们都是最终的和私有的,而且可能有通过类型橡皮擦来的,所以我们需要通用的东西应用于任何出版商,因此操作员

extension Publisher {
    public func countingSubscribers(_ callback: ((Int) -> Void)? = nil)
        -> Publishers.SubscribersCounter<Self> {
            return Publishers.SubscribersCounter<Self>(upstream: self, callback: callback)
    }
}
<P>2,当它在链的中间某个地方,然后接收关于更改的订户计数< /P>的回调。
let publisher = URLSession.shared
        .dataTaskPublisher(for: URL(string: "https://www.google.com")!)
        .countingSubscribers({ count in print("Observers: \(count)") })
        .receive(on: DispatchQueue.main)
        .map { _ in "Data received" }
        .replaceError(with: "An error occurred")
以下是实施:

import Combine

extension Publishers {

    public class SubscribersCounter<Upstream> : Publisher where Upstream : Publisher {

        private(set) var numberOfSubscribers = 0

        public typealias Output = Upstream.Output
        public typealias Failure = Upstream.Failure

        public let upstream: Upstream
        public let callback: ((Int) -> Void)?

        public init(upstream: Upstream, callback: ((Int) -> Void)?) {
            self.upstream = upstream
            self.callback = callback
        }

        public func receive<S>(subscriber: S) where S : Subscriber,
            Upstream.Failure == S.Failure, Upstream.Output == S.Input {
                self.increase()
                upstream.receive(subscriber: SubscribersCounterSubscriber<S>(counter: self, subscriber: subscriber))
        }

        fileprivate func increase() {
            numberOfSubscribers += 1
            self.callback?(numberOfSubscribers)
        }

        fileprivate func decrease() {
            numberOfSubscribers -= 1
            self.callback?(numberOfSubscribers)
        }

        // own subscriber is needed to intercept upstream/downstream events
        private class SubscribersCounterSubscriber<S> : Subscriber where S: Subscriber {
            let counter: SubscribersCounter<Upstream>
            let subscriber: S

            init (counter: SubscribersCounter<Upstream>, subscriber: S) {
                self.counter = counter
                self.subscriber = subscriber
            }

            deinit {
                Swift.print(">> Subscriber deinit")
            }

            func receive(subscription: Subscription) {
                subscriber.receive(subscription: SubscribersCounterSubscription<Upstream>(counter: counter, subscription: subscription))
            }

            func receive(_ input: S.Input) -> Subscribers.Demand {
                return subscriber.receive(input)
            }

            func receive(completion: Subscribers.Completion<S.Failure>) {
                subscriber.receive(completion: completion)
            }

            typealias Input = S.Input
            typealias Failure = S.Failure
        }

        // own subcription is needed to handle cancel and decrease
        private class SubscribersCounterSubscription<Upstream>: Subscription where Upstream: Publisher {
            let counter: SubscribersCounter<Upstream>
            let wrapped: Subscription

            private var cancelled = false
            init(counter: SubscribersCounter<Upstream>, subscription: Subscription) {
                self.counter = counter
                self.wrapped = subscription
            }

            deinit {
                Swift.print(">> Subscription deinit")
                if !cancelled {
                    counter.decrease()
                }
            }

            func request(_ demand: Subscribers.Demand) {
                wrapped.request(demand)
            }

            func cancel() {
                wrapped.cancel()
                if !cancelled {
                    cancelled = true
                    counter.decrease()
                }
            }
        }
    }
}

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

私有枚举计数器更改:Int,可等于{ 案例增加=1 病例减少=-1 } 扩展发布程序{ func trackNumberOfSubscribers _notifyChange:@escaping Int->Void ->任何出版商{ var counter=NSNumber.initvalue:0 设nsLock=nsLock func updateCounter_uchange:CounterChange,notify:Int->Void{ 锁 counter=NSNumbervalue:counter.intValue+change.rawValue notifycounter.intValue nsLock.unlock } 回风口 receiveSubscription:{在updateCounter.Incremented中,notify:notifyChange}, receiveCompletion:{uu在updateCounter.reduced中,notify:notifyChange}, receiveCancel:{updateCounter.Reduced,notify:notifyChange} .橡皮擦出版商 } } 以下是一些测试:

导入测试 进口联合收割机 最终类PublisherTrackNumberOfSubscriberTest:TestCase{ func测试\u四个用户\u完成\u按\u完成{ doTest{publisher在中 publisher.sendcompletion:。已完成 } } func测试\u四个订户\u逐个完成\u错误{ doTest{publisher在中 publisher.sendcompletion:.failure.init } } } 专用扩展PublisherTrackNumberOfSubscriberTest{ 结构EmptyError:Swift.Error{} func doTest_uuline:UInt=line,完成:PassthroughSubject->Void{ 让publisher=PassthroughSubject 变量numberOfSubscriptions=[Int] 让trackable=publisher.trackNumberOfSubscribers{counter in numberOfSubscriptions.appendcounter } func订阅->可取消{ 返回trackable.sinkreceiveCompletion:{uIn},receiveValue:{uIn} } 让Cancelable1=订阅 让Cancelable2=订阅 让Cancelable3=订阅 让Cancelable4=订阅 xctasertnotnillable1,行:行 xctasertnotnillable2,行:行 xctasertnotnillable3,行:行 xctasertnotnillable4,行:行 可取消的1.取消 可取消的2.取消 完成发布器 xctasertequalnumberofsubscriptions[1,2,3,4,3,2,1,0],行:行 } }
在发布我的问题一段时间后,我写了这个简单的扩展。比@Asperi的解决方案简单得多。除了我的简单性之外,我不确定这两种解决方案之间的优缺点

私有枚举计数器更改:Int,可等于{ 案例增加=1 病例减少=-1 } 扩展发布程序{ func trackNumberOfSubscribers _notifyChange:@escaping Int->Void ->任何出版商{ var counter=NSNumber.initvalue:0 设nsLock=nsLock func updateCounter_uchange:CounterChange,notify:Int->Void{ 锁 counter=NSNumbervalue:counter.intValue+change.rawValue notifycounter.intValue nsLock .解锁 } 回风口 receiveSubscription:{在updateCounter.Incremented中,notify:notifyChange}, receiveCompletion:{uu在updateCounter.reduced中,notify:notifyChange}, receiveCancel:{updateCounter.Reduced,notify:notifyChange} .橡皮擦出版商 } } 以下是一些测试:

导入测试 进口联合收割机 最终类PublisherTrackNumberOfSubscriberTest:TestCase{ func测试\u四个用户\u完成\u按\u完成{ doTest{publisher在中 publisher.sendcompletion:。已完成 } } func测试\u四个订户\u逐个完成\u错误{ doTest{publisher在中 publisher.sendcompletion:.failure.init } } } 专用扩展PublisherTrackNumberOfSubscriberTest{ 结构EmptyError:Swift.Error{} func doTest_uuline:UInt=line,完成:PassthroughSubject->Void{ 让publisher=PassthroughSubject 变量numberOfSubscriptions=[Int] 让trackable=publisher.trackNumberOfSubscribers{counter in numberOfSubscriptions.appendcounter } func订阅->可取消{ 返回trackable.sinkreceiveCompletion:{uIn},receiveValue:{uIn} } 让Cancelable1=订阅 让Cancelable2=订阅 让Cancelable3=订阅 让Cancelable4=订阅 xctasertnotnillable1,行:行 xctasertnotnillable2,行:行 xctasertnotnillable3,行:行 xctasertnotnillable4,行:行 可取消的1.取消 可取消的2.取消 完成发布器 xctasertequalnumberofsubscriptions[1,2,3,4,3,2,1,0],行:行 } }