Also habe ich versucht, Target-Action mit Combine verarbeitbar zu machen.
Es ist für macOS, aber wenn Sie es ein wenig ändern, können Sie es mit iOS tun.
Jetzt, da NSControl usw. Publisher zurückgeben kann, sieht es folgendermaßen aus:
let b = NSButton(frame: NSRect(x: 0, y: 0, width: 200, height: 120))
let cancel = b.actionPublisher().sink { print($0) }
b.performClick(nil)
// prints <NSButton: 0xXXXXXXX>
b.performClick(nil)
// prints <NSButton: 0xXXXXXXX>
Da "Ausgabe" von "Publisher" in "Zielaktion" auf "Absender" eingestellt ist, können Sie meiner Meinung nach migrieren, ohne sich zu unwohl zu fühlen.
ActionPublisher Dieser Action Publisher ist normalerweise das einzige, was Benutzer interessieren sollten.
public struct ActionPublisher: Publisher {
public typealias Output = ActionPerfomer
public typealias Failure = Never
private let actionReceiver: ActionReceiver
init(actionPerfomer: Output) {
self.actionReceiver = .init(actionPerfomer: actionPerfomer)
}
public func receive<S: Subscriber>(subscriber: S)
where Failure == S.Failure, Output == S.Input {
actionReceiver.handler = { performer in _ = subscriber.receive(performer) }
subscriber.receive(subscription: ActionSubscription(actionReceiver: actionReceiver))
}
}
ActionSubscription Es wird als "AnyCancellable" angezeigt, wenn die Bearbeitung abgebrochen wird. In der Regel müssen Sie sich jedoch keine Gedanken über die konkrete Form "Action Subscription" machen.
public struct ActionSubscription: Subscription {
public let combineIdentifier = CombineIdentifier()
let actionReceiver: ActionReceiver
public func request(_ demand: Subscribers.Demand) {}
public func cancel() {
actionReceiver.handler = nil
}
}
ActionReceiver Eine Hilfsklasse, die tatsächlich Target-Action verarbeitet. Diese Klasse ist von außen verborgen.
internal final class ActionReceiver: NSObject {
private(set) weak var actionPerfomer: ActionPerfomer!
var handler: ((ActionPerfomer) -> Void)?
init(actionPerfomer: ActionPerfomer) {
self.actionPerfomer = actionPerfomer
super.init()
actionPerfomer.target = self
actionPerfomer.action = #selector(action)
}
@IBAction private func action(_ sender: Any) {
handler?(actionPerfomer)
}
}
ActionPerfomer Dies ist das Protokoll, dem die Klasse entsprechen soll, die in Target-Action zum Absender wird. Da Target-Action unter ziemlich lockeren Bedingungen arbeitet, wird nur das erforderliche Minimum deklariert.
Hier sind "NSControl" und "NSMenuItem", die im Allgemeinen Absender sein können, kompatibel.
Außerdem ist die Methode zum Abrufen von "ActionPublisher" als Erweiterung implementiert.
public protocol ActionPerfomer: AnyObject {
var target: AnyObject? { get set }
var action: Selector? { get set }
}
extension NSControl: ActionPerfomer {}
extension NSMenuItem: ActionPerfomer {}
extension ActionPerfomer {
func actionPublisher() -> ActionPublisher {
.init(actionPerfomer: self)
}
}