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