
Was ist der Unterschied zwischen dem ersten und dem zweiten Beispiel?
Wofür ist das Ziel verantwortlich?
In welchem Fall wird die Methode aufgerufen, wenn auf die Schaltfläche geklickt wird?
TL; DR
Wenn Sie auf eine Schaltfläche klicken, wird unsere Methode in beiden Fällen aufgerufen.
Nur im ersten Beispiel versucht UIKit , die Methode im zugewiesenen Ziel ViewController
(wir haben ViewController
). Es stürzt ab, wenn diese Methode nicht existiert.
Im zweiten Beispiel wird die iOS-Responderkette verwendet. UIKit
sucht nach dem nächsten UIResponder
-a mit dieser Methode. Es wird keinen Absturz geben, wenn unsere Methode nicht gefunden wird.
UIViewController, UIView, UIApplication
erben von UIResponder
.
iOS Responder Chain und was unter der Haube ist
Der UIKit
Prozess der iOS-Responderkette wird von UIKit
, das dynamisch mit einer verknüpften Liste von UIResponder
. Diese UIKit
Liste UIKit
vom Ersthelfer erstellt (dem ersten UIResponder
, der das Ereignis registriert hat, wir haben UIButton(UIView)
und seine subviews
.

UIKit geht die Liste der UIResponder
und überprüft mit canPerformAction
unsere Funktion.
open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool
Wenn der ausgewählte UIResponder
nicht mit einer bestimmten Methode arbeiten kann,
UIKit
sendet rekursiv Aktionen mit der target
, die den nächsten UIResponder
zurückgibt, an den nächsten UIResponder
in der Liste.
open func target(forAction action: Selector, withSender sender: Any?) -> Any?
Dieser Vorgang wird wiederholt, bis einer der UIResponder
mit unserer Methode arbeiten kann oder die Liste endet und das System dieses Ereignis ignoriert.
Im Beispiel für den zweiten Klick wurde es vom UIViewController
, aber UIKit
zuerst eine Anfrage an das UIView
da es der Ersthelfer war. UIKit
die erforderliche Methode nicht vorhanden war, leitete UIKit
Aktionen an den nächsten UIResponder
in einer verknüpften Liste um, der der UIViewController
mit der gewünschten Methode war.
In den meisten Fällen handelt es sich bei der iOS Responder Chain
um eine einfache subviews
Liste von subviews
, deren Reihenfolge jedoch geändert werden kann. Sie können UIResponder (becomeFirstResponder)
werden lassen
zuerst UIResponder
und bringen Sie es mit resignFirstResponder
an die alte Position resignFirstResponder
. Dies wird häufig mit einem UITextField
, um die Tastatur UITextField
, die nur aufgerufen wird, wenn das UITextField
der first responder
.
iOS Responder Chain und UIEvent
Die Responder-Kette ist auch an der Berührung des Bildschirms, Bewegungen und Klicks beteiligt. Wenn das System ein Ereignis erkennt (berühren, bewegen, fernsteuern, drücken), wird ein UIEvent
unter der Haube erstellt und mit der Methode UIApplication.shared.sendEvent()
an UIWindow
. Nach dem Empfang des Ereignisses bestimmt UIWindow
mithilfe der hitTest:withEvent
zu welchem UIResponder
dieses Ereignis gehört, und weist ihm den first responder
. Als nächstes folgt die oben beschriebene Arbeit mit einer verknüpften Liste von UIResponder
.
Um mit System- UIEvent
, können Unterklassen von UIResponder (UIViewController, UIView, UIApplication)
diese Methoden überschreiben:
open func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) open func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) open func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) open func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) open func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func pressesChanged(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func pressesEnded(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func pressesCancelled(_ presses: Set<UIPress>, with event: UIPressesEvent?) open func motionBegan(_ motion: UIEvent.EventSubtype, with event: UIEvent?) open func motionEnded(_ motion: UIEvent.EventSubtype, with event: UIEvent?) open func motionCancelled(_ motion: UIEvent.EventSubtype, with event: UIEvent?) open func remoteControlReceived(with event: UIEvent?)
Trotz der Tatsache, dass sendEvent
manuell sendEvent
und sendEvent
werden kann, ist UIResponder
nicht dafür vorgesehen. Dies kann zu vielen Problemen beim Betrieb benutzerdefinierter Ereignisse führen, die zu unverständlichen Aktionen führen können, die von einem zufälligen first responeder
, der auf Ihr Ereignis reagieren kann.
Warum es nützlich ist, wo zu verwenden
Trotz der Tatsache, dass die iOS Responder Chain
vollständig von UIKit
gesteuert wird, kann sie zur Lösung des Problems der Delegierung / Kommunikation verwendet werden. UIResponder
Aktionen ähneln einmaligen NotificationCenter.default.post
.
Nehmen wir ein Beispiel: Wir haben einen UIViewController
, der sich tief im UINavigationController-Stapel befindet, und wir müssen ihm mitteilen, was passiert ist, als auf eine Schaltfläche auf einem anderen Bildschirm geklickt wurde. Sie können das Delagate-Muster oder NotificationCenter.default.post
. Eine relativ einfache Option ist jedoch die Verwendung der iOS Responder Chain
.
button.addTarget(nil, action: #selector(RootVC.doSomething), for: .touchUpInside)
Wenn diese UIViewController
gedrückt wird, wird die Methode im UIViewController
aufgerufen. #selector kann die folgenden Parameter annehmen:
@objc func doSomething() @objc func doSomething(sender: Any?) @objc func doSomething(sender: Any?, event: UIEvent?)
Absender ist das Objekt, das das Ereignis gesendet hat - UIButton, UITextField usw.
Zusätzliche Ressourcen zum Lernen [deu]:
Gute Beschreibung von UIEvent, UIResponder und einigen fortgeschrittenen Beispielen (Patern-Koordinator)
Lesen Sie mehr über die ios-Responderkette
Beispiel für eine Antwortkette in der Praxis
Off Dock in der iOS-Responderkette
Off Dock von UIResponder