

テーブルビューの使い方について聞きたいのですが、

下記ソースを想定した、1行のセル内に複数のボタンを配置させたとき、  
どのボタンが配置されたかのイベントを上位のクラス(ViewControllerなど)で判別することは可能でしょうか？  
方法が分からず、行き詰ってます。ご教授ください。

**VIewController.swift**

[code]

    class ViewController:UITableViewController{
    　・・・
    　// セルの内容を設定するメソッド
      override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
          if(indexPath.row == 0){
            // 【注目】
            let cell = tableView.dequeueReusableCell(withIdentifier: "testcell", for: indexPath) as! myCusutomCell
            return cell
    　　　　・・・・
         }
         ・・・・
       }
    
       // myCusutomCellの中にある複数のボタンのタップ情報をここで（ViewController内で）受けたい
    
    }
    
    // testcell
    class myCusutomCell:UITableViewCell{
    
    　button1 ~
      button2 ~
      button3 ~
    
    }
    
[/code]


CC BY-SA 4.0
2020-01-16T11:20:41.370
62297
2020-01-18T05:26:59.020
37089
question
swift tableview
UITableViewCell 1行の中に複数配置されたUIButtonのタップイベントを、上位クラス(ViewContoller)で受ける方法


2種類の方法をご紹介します。まず、レスポンダーチェーンを使う方法です。

## Responder Chainによるイベントの受け渡し

レスポンダーチェーンは、Macのアプリケーションを開発した経験のある方なら、メニューバーのメニュー実装などでよく使われる手法なのですが、iOSのアプリ開発では、直接はあまりお目にかかりません。しかし、タッチイベント（`func
touchesBegan(_ touches: Set<UITouch>, with event:
UIEvent?)`）の伝播など、影で活躍しているメカニズムなので、しっかり学習し、理解しなければいけません。  
レスポンダーチェーンとは、そのまま直訳した「応答の鎖」がよく表現しているように、ユーザなどが起こしたイベントを、複数の鎖で繋がれた`UIResponder`のオブジェクトの間で、次々に受け渡していく機構です。鎖のどこかのオブジェクトに、イベントを処理するアクションメソッド（`@IBAction`）が実装されていると、そこでアクションメソッドが実行されます。  
Storyboardの編集画面で、View Controllerに"First
Responder"という項目があるのに、お気づきになりましたか？これがレスポンダーチェーンの先端を意味します。

[![画像の説明をここに入力](https://i.stack.imgur.com/fmtPi.png)](https://i.stack.imgur.com/fmtPi.png)

First
Responderのアイコンにボタンなどの`UIControl`オブジェクトから接続（Connect）をすると、特定のオブジェクトにではなく、レスポンダーチェーンに命令（Action）を送ることができます。  
まず、First ResponderのAttributes
Inspectorを表示し、新規アクションを登録します。下図では、`doSomething`というアクションを登録しています。「Type」は、今回は汎用性を考えて、`NSObject`としています。

[![画像の説明をここに入力](https://i.stack.imgur.com/chHfM.png)](https://i.stack.imgur.com/chHfM.png)

ボタンオブジェクトからFirst
Responderに接続（Connect）を行うと、プルダウンメニューの中に、先ほど登録したアクション`doSomething`が見つかりますので、それを選択します。

[![画像の説明をここに入力](https://i.stack.imgur.com/8Y6FB.png)](https://i.stack.imgur.com/8Y6FB.png)

これでStoryboardの編集は完了です。次に、`ViewController`クラスに、イベントを受け取るアクションメソッドを実装します。

[code]

    class ViewController: UITableViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
        }
    
        @IBAction func doSomething(_ sender: Any) {
            print("Hello")
        }
    
        ........
    }
    
[/code]

以上の編集で、テーブルセル上のボタンをタップすると、「Hello」が出力されるようになります。  
`UIViewController`のサブクラスは、オートマチックにレスポンダーチェーンの最後に近い方に位置付けられるので、ほぼどのようなイベントも受け取ることができます。

First Responderへの接続を、Storyboardでなく、プログラムで行う場合は、`UIControl`クラスのメソッド、[`Instance
Method
addTarget(_:action:for:)`](https://developer.apple.com/documentation/uikit/uicontrol/1618259-addtarget)を使います。このメソッドの引数`target`の型がオプショナル（Any?）であることに注目して、リファレンスの説明をご覧ください。

> target  
>  The target object—that is, the object whose action method is  
>  called. If you specify nil, UIKit searches the responder chain for an  
>  object that responds to the specified action message and delivers the  
>  message to that object.

「If you specify
nil,」の後「UIKitは、レスポンダーチェーンの中から、セレクタ（`action:`）に応答するオブジェクトを探し出し、そのオブジェクトにアクションを送り届けます」とあるところは、そのままレスポンダーチェーンを簡潔に説明した文になっています。

* * *

## Table ViewをStatic Cellsモードにする

[![画像の説明をここに入力](https://i.stack.imgur.com/lrhON.png)](https://i.stack.imgur.com/lrhON.png)

`UITableViewController`のもとにあるTable Viewは、Static
Cellsというモードにできます。その名のとおり、セルを動的に再利用するメカニズムを使わずに、セルを静的に配置するものですが、このモードでは、セル上に配置したボタン類のコントロール（`UIControl`）と、`UITableViewController`サブクラスに定義したアクションメソッド（`@IBAction`）を接続できるという利点があります。「ボタンがセル上にあるから……」という意識をせずに、Storyboard上の編集だけで完結するメリットは大きいでしょう。


CC BY-SA 4.0
2020-01-16T22:25:07.973
62306
2020-01-18T05:26:59.020
2020-01-18T05:26:59.020
18540
18540
62297
answer