如何让Combine订阅者仅接收数组发布者中的4个元素?
如何让Combine订阅者仅接收数组发布者中的4个元素?
嘿,我来帮你捋捋问题出在哪~
你现在的代码里,receive(subscription:) 方法确实请求了4个元素,但问题出在 receive(_ input:) 方法的返回值上!每次你收到一个元素后,都返回了 .max(4),这相当于在告诉发布者“再给我4个元素”。而数组发布者是同步的,它会立刻把剩下的元素一股脑发出来,直到没有元素为止,所以你才会收到全部7个元素。
要解决这个问题,有两种常见的思路:
方法一:修改receive(_ input:)的返回值为.none
只要把receive方法里的返回值改成.none,就表示你收到当前元素后不再需要更多元素了。这样一开始请求的4个元素发完后,发布者就会停止发送:
func receive(_ input: T) -> Subscribers.Demand { print("input,", input) return .none // 不再请求更多元素 }
方法二:跟踪已接收元素数量(更灵活的方式)
如果以后你需要动态调整接收数量,可以在订阅者里加一个计数器,当收到的元素达到你设定的最大值时,返回.none甚至主动取消订阅:
struct ArraySubscriber<T>: Subscriber { typealias Input = T typealias Failure = Never let combineIdentifier = CombineIdentifier() private var receivedCount = 0 private let maxElements: Int // 初始化时传入最大接收数量 init(maxElements: Int) { self.maxElements = maxElements } func receive(subscription: any Subscription) { subscription.request(.max(maxElements)) } func receive(_ input: T) -> Subscribers.Demand { print("input,", input) receivedCount += 1 // 达到数量后不再请求更多 if receivedCount >= maxElements { return .none } // 这里也可以返回.none,因为初始请求已经涵盖了所有需要的数量 return .none } func receive(completion: Subscribers.Completion<Never>) { switch completion { case .finished: print("publisher finished normally") case .failure(let failure): print("publisher failed due to, ", failure) } } } // 使用时传入最大数量4 let subscriber = ArraySubscriber<Int>(maxElements: 4) array.publisher.subscribe(subscriber)
额外小提示
其实如果不需要自定义订阅者的话,Combine提供了更简洁的方式:直接用prefix(4)操作符配合sink,一行代码就能搞定:
// 记得先定义一个 cancellables 集合保存订阅 var cancellables = Set<AnyCancellable>() array.publisher .prefix(4) .sink { completion in switch completion { case .finished: print("publisher finished normally") case .failure(let error): print("failed: \(error)") } } receiveValue: { value in print("input,", value) } .store(in: &cancellables)
这样不管是自定义订阅者还是用内置操作符,都能轻松实现只接收前4个元素的需求啦~
内容来源于stack exchange
相关产品推荐
相关产品推荐

