UIControl.swift 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. //
  2. // UIControl.swift
  3. // Mastodon
  4. //
  5. // Created by sxiaojian on 2021/3/8.
  6. //
  7. import Foundation
  8. import UIKit
  9. import Combine
  10. /// A custom subscription to capture UIControl target events.
  11. final class UIControlSubscription<SubscriberType: Subscriber, Control: UIControl>: Subscription where SubscriberType.Input == Control {
  12. private var subscriber: SubscriberType?
  13. private let control: Control
  14. init(subscriber: SubscriberType, control: Control, event: UIControl.Event) {
  15. self.subscriber = subscriber
  16. self.control = control
  17. control.addTarget(self, action: #selector(eventHandler), for: event)
  18. }
  19. func request(_ demand: Subscribers.Demand) {
  20. // We do nothing here as we only want to send events when they occur.
  21. // See, for more info: https://developer.apple.com/documentation/combine/subscribers/demand
  22. }
  23. func cancel() {
  24. subscriber = nil
  25. }
  26. @objc private func eventHandler() {
  27. _ = subscriber?.receive(control)
  28. }
  29. }
  30. /// A custom `Publisher` to work with our custom `UIControlSubscription`.
  31. struct UIControlPublisher<Control: UIControl>: Publisher {
  32. typealias Output = Control
  33. typealias Failure = Never
  34. let control: Control
  35. let controlEvents: UIControl.Event
  36. init(control: Control, events: UIControl.Event) {
  37. self.control = control
  38. self.controlEvents = events
  39. }
  40. func receive<S>(subscriber: S) where S : Subscriber, S.Failure == UIControlPublisher.Failure, S.Input == UIControlPublisher.Output {
  41. let subscription = UIControlSubscription(subscriber: subscriber, control: control, event: controlEvents)
  42. subscriber.receive(subscription: subscription)
  43. }
  44. }
  45. /// Extending the `UIControl` types to be able to produce a `UIControl.Event` publisher.
  46. protocol CombineCompatible { }
  47. extension UIControl: CombineCompatible { }
  48. extension CombineCompatible where Self: UIControl {
  49. func publisher(for events: UIControl.Event) -> UIControlPublisher<UIControl> {
  50. return UIControlPublisher(control: self, events: events)
  51. }
  52. }