First Responderについて理解する

## はじめに
iOSではアプリ起動時に外的作用であるイベントを待ち続け、

イベントが来たら1つずつ処理をするイベントループと呼ばれる状態が作られる。

イベントの例としては、画面のタッチ、端末のシェイク、サーバからのプッシュ通知などがある。

これらの通知は一時的にイベントキューという場所に格納され、先入先出の順でイベントループにより処理がおこなわれる。

アプリケーションの共通部分となるUIApplicationオブジェクトはこのイベントループを管理し、

受け取ったイベントを適所にディスパッチ(割り振り)している。

## FirstResponderとは

iOSがイベントを検知したときに

一番はじめにイベント処理を試みるUIResponderオブジェクト。

イベント発生時、まずFirstResponderにイベントがディスパッチされ、

FirstResponderでイベントを捌くことができなかった場合に、

Responder Chain(詳細後述)を辿って、処理できるResponderを探す。

FirstResponderになるためには

[canResignFirstResponder](https://developer.apple.com/documentation/uikit/uiresponder/1621125-canresignfirstresponder)プロパティをtrueを返すようにし、

[becomeFirstResponder()](https://developer.apple.com/documentation/uikit/uiresponder/1621113-becomefirstresponder)メソッドでFirstResponderになることを宣言する。

```swift
import UIKit

class SampleViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // View表示時にFirstResponderになることを宣言 
        self.becomeFirstResponder()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // Viewが非表示時にFirstResponderをやめる
        self.resignFirstResponder()
        
        
    }
    
    // このViewControllerがFirstResponderになれるようにする
    override var canBecomeFirstResponder: Bool {
        return true
    }
    
}
```

- [func becomeFirstResponder() -> Bool](https://developer.apple.com/documentation/uikit/uiresponder/1621113-becomefirstresponder)
- [var canResignFirstResponder: Bool](https://developer.apple.com/documentation/uikit/uiresponder/1621125-canresignfirstresponder)

## そもそもUIResponderとは

イベントに応答して処理するための抽象的なインターフェース

[Apple公式](https://developer.apple.com/documentation/uikit/uiresponder/)

より具体的に書くと、

「UILabelなどUIControlのサブクラスではないUI部品において、

iOSが検知したtouchイベントなどを処理するためのクラス」

UIViewやUIViewController、UIViewを継承しているUIWindow、AppDelagate、UIApplicationなどは、UIResponderを継承している。

そのため、UIButtonのように自分自身がタッチされたことを検知できる仕組みを持っていなくても、

UIResponderのメソッドをオーバーライドすることでイベントを処理することができる。

例えばtouchイベントの場合

UIResponderのサブクラスで以下のようなメソッドをオーバーライドすることができる。

### touchesBegan(_:with:)

viewやwindowなどに、1本以上の指が触れたときに呼ばれる

[func touchesBegan(Set<UITouch>, with: UIEvent?)](https://developer.apple.com/documentation/uikit/uiresponder/1621142-touchesbegan)

### touchesMoved(_:with:)

viewやwindowなどで、1本以上の指が動いたときに呼ばれる

[func touchesMoved(Set<UITouch>, with: UIEvent?)](https://developer.apple.com/documentation/uikit/uiresponder/1621107-touchesmoved)

### touchesEnded(_:with:)

viewやwindowなどで、1本以上の指が離れたときに呼ばれる

[func touchesEnded(Set<UITouch>, with: UIEvent?)](https://developer.apple.com/documentation/uikit/uiresponder/1621084-touchesended)

### touchesCancelled(_:with:)

システムイベント（システムアラートなど）によりタッチがキャンセルされたときに呼ばれる

[func touchesCancelled(Set<UITouch>, with: UIEvent?)](https://developer.apple.com/documentation/uikit/uiresponder/1621116-touchescancelled)

## Responder Chainとは

iOSが検知したイベントを処理できるオブジェクトが見つかるまで、

イベントを順次リレーする仕組み。

検知されたイベントはUIApplicationオブジェクトからUIWindowオブジェクトへ渡され、

UIWindowオブジェクトはそのイベントに最も相応しいと思われるオブジェクトにそのイベントをディスパッチする。この時、オブジェクトがイベントを処理できない(=ハンドラがない)場合、

処理可能なオブジェクトが見つかるまで上位のスコープにイベントが渡される。

このようなイベントをリレーするオブジェクトの連鎖がResponderChain。

ResponderChainはイベントにより動的に作成される。

例えばtouchイベントの場合、下記のHitTest(当たり判定)を用いてResponder Chainを形成する。

### HitTestの流れ

UIViewが持つhitTest(_ : withEvent)メソッドが、

その内部でpointInside(_ : withEvent)メソッドを呼び

自分のsubViewのうちどれがタッチされたのかを返す

例として下記の図では、

ViewA上にあるViewCをタッチした場合のHitTestを行なっている。

![hitTest.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/741978/20cd548f-1d30-f0e7-4b21-0cd5d422cc59.png)


## まとめ

FirstResponderは一番はじめにイベント処理を試みるUIResponderオブジェクトとして

システムに明示的に伝えるもの。

iOSで検知されたイベントはFirstResponderに渡され、

FirstResponderが処理できない場合はResponderChainを使って、次のオブジェクトにイベントがリレーされる。


間違いやご指摘などありましたら、コメントにてご教授いただけますと幸いです。

## 参考

[Apple Developer Documentation](https://developer.apple.com/documentation/uikit/uiresponder)

[【Swift】Responder Chainの仕組み - Qiita](https://qiita.com/shiz/items/5a75fbd903de4a474b1d)

[UIKit＆Swiftプログラミング　優れたiPhoneアプリ開発のためのUI実装ガイド](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwigkMrjrezzAhXRBKYKHZtSAm0QFnoECAgQAQ&url=https%3A%2F%2Fwww.amazon.co.jp%2FUIKit%25EF%25BC%2586Swift%25E3%2583%2597%25E3%2583%25AD%25E3%2582%25B0%25E3%2583%25A9%25E3%2583%259F%25E3%2583%25B3%25E3%2582%25B0-%25E5%2584%25AA%25E3%2582%258C%25E3%2581%259FiPhone%25E3%2582%25A2%25E3%2583%2597%25E3%2583%25AA%25E9%2596%258B%25E7%2599%25BA%25E3%2581%25AE%25E3%2581%259F%25E3%2582%2581%25E3%2581%25AEUI%25E5%25AE%259F%25E8%25A3%2585%25E3%2582%25AC%25E3%2582%25A4%25E3%2583%2589-%25E6%2596%2589%25E8%2597%25A4-%25E7%25A5%2590%25E8%25BC%2594-ebook%2Fdp%2FB00ZF44J8K&usg=AOvVaw2-i7qkWr8MNVvRF2kEKQtJ)