【Swift】addTargetメソッドの基礎的な理解

たぶん初学者でも`addTarget`メソッドを実装しようと思えば、エラーで躓くことはあっても、なんとなく実装できてしまうものだと思います。でも、少し時間をおいてしまうとたぶんまたよくわからないままに実装することになります。ここにいたってきちんと理解しなければと気づくのですが、たぶん問題は`addTarget`そのものではなくて、それぞれのパラメータが意味する部分やクラスのプロパティやメソッドの表現の仕方、そうした基礎的な文法、言語の知識の不足からくるものではないかと考えます。とさも当然のように自分の経験を一般化して話をしていますが、ここにいたってのまさにここにいるのがワイです。なにもかも、ワイの頭のコンパイラが悪いんだ。

このQiitaでは、iOSアプリ開発で基本的なインスタンスメソッドであるaddTargetをそれぞれのパラメータの意味や理解を通じて把握していくことを目指します。

#addTarget(_:action:for:)

```swift
func addTarget(_ target: Any?, 
                 action: Selector, 
      for controlEvents: UIControl.Event)
```

サンプル

```swift
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        let button = UIButton(type: .system)
        button.setTitle("Button", for: .normal)
        button.setTitleColor(UIColor.white, for: .normal)
        button.backgroundColor = UIColor.black
        button.frame = CGRect(x: view.center.x-50,
                              y: view.center.y-50,
                              width: 100,
                              height: 100)
        button.translatesAutoresizingMaskIntoConstraints = false
        self.view.addSubview(button)
        
        //次の一文
        button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
    }

    @objc func buttonTapped(){
        print("buttonがタップされました")
    }

```

まずインスタンスメソッドであるため、実装にはインスタンスを用意する必要があります。ここでは省きますが、上記のbuttonをUIButtonのインスタンスとしてコード上で記載しています。

#Parameters

##targeｔ　

ドキュメントには**The target object—that is, the object whose action method is called.**と書かれており、actionメソッドが属しているオブジェクトを指定するパラメータとなります。逆に言えば、そのオブジェクトのメソッドを呼ぶということです。Any型のオプショナルであるため、基本的にどんな型でも指定できます。とはいえネットに上がっているものはサンプルが多く、そのViewController内に記載されているため、たいていはselfとして呼ばれています。

またnilも許容されており、その場合はactionやObjectへの
nilである場合はUIKitがオブジェクトに対するactionメッセージを特定し伝えられとされています。
試しに上記サンプルコードでnilにしてみましたが、コンパイルも実行も問題なく行えました。

```swift
button.addTarget(nil, action: #selector(buttonTapped), for: .touchUpInside)
```


##action
actionメソッドを特定するセレクタ。ここでどのメソッドをactionとするかを設定する。
一般にはList１の表現とマッチするようなセレクターが指定される。
nilは許されないため、必ず指定しなければならない。

Listing 1 Action method signatures
`@IBAction func doSomething()`
`@IBAction func doSomething(sender: UIButton)`
`@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)`

*sender は送信者という意味

##controlEvents
actionをコントロールする具体的なイベントを示すビットマスク。
常に少なくとも１つの定数を指定しなければならない。
要するにタッチするとか、押し続けるとかそうした操作（＝イベント）を示せということ。
そうした操作は定数として記述されているから、定数を指定なんてことになるわけですね。

#Selectorとは

ちなみにセレクタ（Selector）とは、Swiftの前身であるObjective-Cの概念です。

といっても、Swiftという言語の純粋な仕様にはないだけであり、他の言語一般にはセレクタは存在します。またSwiftでもセレクタを必要とする場合はあるため、こうした部分はObjective-Cを通して利用しています。Objective-Cを利用する場合には。セレクタが取るパラメータに`@objc`という属性を付けなければいけません。時々みかける`＠objc`というのはObjective-Cの略称なんですね。

##Selector Expression

https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#grammar_selector-expression

実際のセレクタはどのように表現するかというと、
`#selector(method name)`
`#selector(getter: property name)`
`#selector(setter: property name)`

もちろんセレクタはObjective-Cの概念であるため、そのランタイム時に利用できるように上記メソッドやプロパティの名称に＠objcを付けて参照できるようにしなければなりません。

##Selectorの書き方

書き方としては
・＃Selector
・Selector
・文字列のみ
の３つの方法がありますが、実際に使用されているのは＃Selectorです。＃Selectorにはコンパイラチェックが働きエラーが表示されるのですが、他２つに関しては表示されずエラーは実行時エラーのみです。#Selectorが使われるのはこのような理由からだと思われます。

またSelectorがパラメータとして受け取れるのは２つまでで、UIButtonとUIEventに限られるのだそうです。たしかにExpressionの部分でも表記したとおり、下記の表現は最大でsenderとeventの指定のみとなっています。

Listing 1 Action method signatures
`@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)`

#UIControl.Eventの種類

**UIcontrolとは**

`class UIControl : UIView`

UIViewを継承したクラスです。名前の通り、user interactionに対する操作や指示を伝えます。

**UIControl.Eventとは**

`struct Event`

Event自体はstruct型、構造体です。そしてその構造体に含まれるプロパティは次の通りです。
UIKitはUIパーツの初期設定と言えるので、そのプロパティもすべてスタティックで、Event型に紐付いています。よく使われているのはtouchUpInsideです。コメントにあるように、指がコントロールの内部をタッチアップ、触れたときをイベントとして扱うプロパティです。

addTargetのパラメータの型はUIcontrol.Eventと構造体までの型が指定されているので、記述は .touchUpInside と省略できます。

```swift
static var touchDown: UIControl.Event　//A touch-down event in the control.
static var touchDownRepeat: UIControl.Event //A repeated touch-down event in the control; for this event the value of the UITouch tapCount method is greater than one.
static var touchDragInside: UIControl.Event //An event where a finger is dragged inside the bounds of the control.
static var touchDragOutside: UIControl.Event //An event where a finger is dragged just outside the bounds of the control.
static var touchDragEnter: UIControl.Event//An event where a finger is dragged into the bounds of the control. 
static var touchDragExit: UIControl.Event //An event where a finger is dragged from within a control to outside its bounds.

static var touchUpInside: UIControl.Event //A touch-up event in the control where the finger is inside the bounds of the control.

static var touchUpOutside: UIControl.Event //A touch-up event in the control where the finger is outside the bounds of the control.
static var touchCancel: UIControl.Event //A system event canceling the current touches for the control.
static var valueChanged: UIControl.Event //A touch dragging or otherwise manipulating a control, causing it to emit a series of different values. 
static var menuActionTriggered: UIControl.Event //A menu action has triggered prior to the menu being presented.
static var primaryActionTriggered: UIControl.Event //A semantic action triggered by buttons.
static var editingDidBegin: UIControl.Event //A touch initiating an editing session in a UITextField object by entering its bounds.
static var editingChanged: UIControl.Event //A touch making an editing change in a UITextField object.
static var editingDidEnd: UIControl.Event //A touch ending an editing session in a UITextField object by leaving its bounds.
static var editingDidEndOnExit: UIControl.Event //A touch ending an editing session in a UITextField object.
static var allTouchEvents: UIControl.Event //All touch events.
static var allEditingEvents: UIControl.Event //All editing touches for UITextField objects.
static var applicationReserved: UIControl.Event //A range of control-event values available for application use.
static var systemReserved: UIControl.Event //A range of control-event values reserved for internal framework use.
static var allEvents: UIControl.Event //All events, including system events.
```

#所感

　addTargetひとつとっても、単にそのメソッドがなにをするメソッドなのかではなくて、それ以前になにを指定しているのか、指定するためにはなにを必要とするのか、どうしてそのような書き方をしなければならないのかといったことがわからないと、うまく飲み込めなかったため、まとめてみました。すべてを覚えることは土台無理ですので、UIcontrolなども覚えるべきものではなくて、一通り知っておく、あるいは調べて読めばわかる程度でいいはずです。ただ、そのためには基本となる言語の背景や文法的な知識が不可欠だと思いました。というか文系脳であれなんですが、英文解釈みたいだ。

#参考

addTarget(_:action:for:)
https://developer.apple.com/documentation/uikit/uicontrol/1618259-addtarget

Selector完全攻略、そして初学者特有のAddTarget()やAddObserver()のセレクタに変数を渡そうとする願望について
https://qiita.com/st43/items/43c5c0f5e1f727ba0ff0#selector