iOS Responder Chain oder was sie beim Interview fragen

Bild


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 .


Bild


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

Source: https://habr.com/ru/post/de464463/


All Articles