質問: tableView.dequeueReusableCell(withIdentifier: "testcell", for: indexPath) as! myCusutomCell return cell ・・・・ } ・・・・ } // myCusutomCellの中にある複数のボタンのタップ情報をここで(ViewController内で)受けたい } // testcell class myCusutomCell:UITableViewCell{ button1 ~ button2 ~ button3 ~ } ```
回答: 2種類の方法をご紹介します。まず、レスポンダーチェーンを使う方法です。 Responder Chainによるイベントの受け渡し レスポンダーチェーンは、Macのアプリケーションを開発した経験のある方なら、メニューバーのメニュー実装などでよく使われる手法なのですが、iOSのアプリ開発では、直接はあまりお目にかかりません。しかし、タッチイベント(`func touchesBegan(_ touches: Set, with event: UIEvent?)`)の伝播など、影で活躍しているメカニズムなので、しっかり学習し、理解しなければいけません。 レスポンダーチェーンとは、そのまま直訳した「応答の鎖」がよく表現しているように、ユーザなどが起こしたイベントを、複数の鎖で繋がれた`UIResponder`のオブジェクトの間で、次々に受け渡していく機構です。鎖のどこかのオブジェクトに、イベントを処理するアクションメソッド(`@IBAction`)が実装されていると、そこでアクションメソッドが実行されます。 Storyboardの編集画面で、View Controllerに"First Responder"という項目があるのに、お気づきになりましたか?これがレスポンダーチェーンの先端を意味します。 !画像の説明をここに入力 First Responderのアイコンにボタンなどの`UIControl`オブジェクトから接続(Connect)をすると、特定のオブジェクトにではなく、レスポンダーチェーンに命令(Action)を送ることができます。 まず、First ResponderのAttributes Inspectorを表示し、新規アクションを登録します。下図では、`doSomething`というアクションを登録しています。「Type」は、今回は汎用性を考えて、`NSObject`としています。 !画像の説明をここに入力 ボタンオブジェクトからFirst Responderに接続(Connect)を行うと、プルダウンメニューの中に、先ほど登録したアクション`doSomething`が見つかりますので、それを選択します。 !画像の説明をここに入力 これでStoryboardの編集は完了です。次に、`ViewController`クラスに、イベントを受け取るアクションメソッドを実装します。 ``` class ViewController: UITableViewController { override func viewDidLoad() { super.viewDidLoad() } @IBAction func doSomething(_ sender: Any) { print("Hello") } ........ } ``` 以上の編集で、テーブルセル上のボタンをタップすると、「Hello」が出力されるようになります。 `UIViewController`のサブクラスは、オートマチックにレスポンダーチェーンの最後に近い方に位置付けられるので、ほぼどのようなイベントも受け取ることができます。 First Responderへの接続を、Storyboardでなく、プログラムで行う場合は、`UIControl`クラスのメソッド、`Instance Method addTarget(_:action:for:)`を使います。このメソッドの引数`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モードにする !画像の説明をここに入力 `UITableViewController`のもとにあるTable Viewは、Static Cellsというモードにできます。その名のとおり、セルを動的に再利用するメカニズムを使わずに、セルを静的に配置するものですが、このモードでは、セル上に配置したボタン類のコントロール(`UIControl`)と、`UITableViewController`サブクラスに定義したアクションメソッド(`@IBAction`)を接続できるという利点があります。「ボタンがセル上にあるから......」という意識をせずに、Storyboard上の編集だけで完結するメリットは大きいでしょう。