Cadeia de respondentes do iOS ou o que eles pedem na entrevista

imagem


Qual é a diferença entre o primeiro e o segundo exemplo?

Qual é o alvo responsável?

Nesse caso, o método é chamado quando o botão é clicado?

TL; DR


Quando um botão é clicado, nosso método é chamado nos dois casos.


Somente no primeiro exemplo, o UIKit tentará chamar o método no destino atribuído (temos o ViewController ). Ele falhará se esse método não existir.


No segundo exemplo, a cadeia de resposta do iOS é usada, o UIKit procurará o UIResponder mais próximo -a, que possui esse método. Não haverá falha se o nosso método não for encontrado.


UIViewController, UIView, UIApplication herdam do UIResponder .


Cadeia de resposta do iOS e o que há por trás


UIKit processo da cadeia de resposta do iOS é tratado pelo UIKit , que trabalha dinamicamente com uma lista vinculada de UIResponder . Essa lista do UIKit criada a partir do primeiro respondedor (o primeiro UIResponder que registrou o evento, temos o UIButton(UIView) e suas subviews .


imagem


O UIKit percorre a lista de UIResponder e verifica com canPerformAction a nossa função.


 open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool 

Se o UIResponder selecionado não puder trabalhar com um método específico,
UIKit envia recursivamente ações para o próximo UIResponder na lista usando o método de target que retorna o próximo UIResponder .


 open func target(forAction action: Selector, withSender sender: Any?) -> Any? 

Esse processo é repetido até que um dos UIResponder possa trabalhar com nosso método ou a lista termine e o sistema ignore esse evento.


No exemplo do segundo clique, ele foi tratado pelo UIViewController , mas o UIKit primeiro enviou uma solicitação ao UIView pois era o primeiro respondedor. Ele não tinha o método necessário; portanto, o UIKit redirecionou as ações para o próximo UIResponder em uma lista vinculada, que era o UIViewController que possuía o método desejado.


Na maioria dos casos, a iOS Responder Chain do iOS Responder Chain é uma simples lista subviews de subviews , mas sua ordem pode ser alterada. Você pode fazer o UIResponder (becomeFirstResponder) se tornar
primeiro UIResponder e retorne à posição antiga usando resignFirstResponder . Isso geralmente é usado com um UITextField para mostrar o teclado que será chamado apenas quando o UITextField for o first responder .


Cadeia de resposta do iOS e UIEvent


A Cadeia de Respondentes também está envolvida em tocar na tela, movimentos, cliques. Quando o sistema detecta algum tipo de evento (toque, movimento, controle remoto, imprensa), um UIEvent é criado sob o capô e enviado usando o método UIApplication.shared.sendEvent() para o UIWindow . Após receber o evento, o UIWindow determina o uso do hitTest:withEvent ao qual esse evento pertence ao UIResponder e atribui a ele o first responder . A seguir, é apresentado o trabalho com uma lista vinculada de UIResponder descrita acima.


Para trabalhar com UIEvent sistema, as subclasses de UIResponder (UIViewController, UIView, UIApplication) podem substituir esses métodos:


 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?) 

Apesar do fato de a capacidade de herdar e chamar sendEvent manualmente estar presente, o UIResponder não se destina a isso. Isso pode criar muitos problemas com a operação de eventos personalizados, o que pode levar a ações incompreensíveis causadas por um first responeder respondente aleatório que pode responder ao seu evento.


Por que é útil, onde usar


Apesar do iOS Responder Chain totalmente controlado pelo UIKit , ele pode ser usado para resolver o problema de delegação / comunicação. UIResponder ações do UIResponder são semelhantes ao NotificationCenter.default.post único.


Vamos dar um exemplo: temos um UIViewController , que está no fundo da pilha UINavigationController e precisamos contar o que aconteceu quando um botão foi clicado em outra tela. Você pode usar o padrão delagate ou NotificationCenter.default.post , mas uma opção bastante simples é usar a iOS Responder Chain do iOS Responder Chain .


 button.addTarget(nil, action: #selector(RootVC.doSomething), for: .touchUpInside) 

Quando pressionado, o método na UIViewController será chamado. #selector pode usar os seguintes parâmetros:


 @objc func doSomething() @objc func doSomething(sender: Any?) @objc func doSomething(sender: Any?, event: UIEvent?) 

remetente é o objeto que enviou o evento - UIButton, UITextField e assim por diante.


Recursos adicionais para aprendizado [eng]:


Boa descrição do UIEvent, UIResponder e alguns exemplos avançados (coordenador patern)
Leia mais sobre a cadeia de resposta do ios
Exemplo de cadeia de respondentes na prática
Off dock na cadeia de resposta do iOS
Off Dock por UIResponder

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


All Articles