質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

1回答

2429閲覧

addTargetでのSelecter、@objc、senderについて

kyokio

総合スコア560

Objective-C

Objective-Cはオブジェクト指向型のプログラミング言語のひとつです。C言語をベースにSmalltalkが取り入れられています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

1クリップ

投稿2020/03/10 11:31

#4つのボタンをコードで追加してみた
今までstoryBoardでUIButtonを追加して紐付けし、処理を書いていました。
しかし、今回はボタン4つを配置し、ボタンの幅を画面の幅をボタンの個数分(今回は4つ)にするのでコードで書いた方が楽だと思い、コードで書いてみました。

##コードでボタンを設置した場合のボタンが押された場合の処理
コードでボタンを設置した場合、ボタンが押された時の処理はaddTargetを使うらしいです。

addTargetの記法は以下

UIButton.addTarget(_ target: Any?, action: Selector, for controlEvents: UIControlEvents)

第一引数は使うメソッドの場所を指定。
第二引数は使うメソッドを指定。
第三引数はどんなイベントが発生したを指定。

今回は以下のようにしました。

ViewController

1func setButtons(){ 2 //設置するボタンの数 3 let NumOfButtons = 4 4 //横幅をスクリーンの幅の設置するボタンの数分の1にする 5 let buttonWidth = UIScreen.main.bounds.width / CGFloat(NumOfButtons) 6 7 for i in 0..<NumOfButtons{ 8 //インスタンス化 9 let Button = UIButton() 10 //ボタンの背景色を設定 11 Button.backgroundColor = .white 12 //ボタンの枠線の色と太さ 13 Button.layer.borderColor = UIColor.black.cgColor 14 Button.layer.borderWidth = 0.5 15 //ボタンの丸枠のカーブの強さ 16 Button.layer.cornerRadius = 5.0 17 //ボタンのフレーム 18 Button.frame = CGRect(x: buttonWidth*CGFloat(i), y: 50, width: buttonWidth, height: 70) 19 //タグをつける 20 Button.tag = i 21 //タイトルとタイトルの文字色 22 Button.setTitle("Button(i)", for: .normal) 23 Button.setTitleColor(.black, for: .normal) 24 25 //ボタンを押した時(touchUpInside)の処理 26 Button.addTarget(self, action: #selector(ButtonTapped(sender:)), for: .touchUpInside) 27 28 //viewにボタンを追加 29 self.view.addSubview(Button) 30 } 31 } 32 33 @objc func ButtonTapped(sender:UIButton){ 34 print(sender.tag) 35 }

CocosTouchではイベントの処理についてはObject-CのAPIあるtarget-actionを利用していて、Object-Cではメソッドを選択するパラメータをselectorという為第二引数にselectorとある。
そして呼び出すメソッドがObject-Cのメソッドとして認識されるように@objc属性を使用する。
ここまではなんとなく理解しました。
(なぜObject-CのAPIを利用してるのかは謎ですが)

##どのボタンが押されたかを知りたい
今回はボタンが4つありどのボタンが押されたかを判断する必要があります。
そのためにtagに番号を振り分けておきました。
最初、以下のように書いたところエラーが出ました。

ViewController

1 Button.addTarget(self, action: #selector(ButtonTapped(tag:i)), for: .touchUpInside) 2 self.view.addSubview(Button) 3} 4 5@objc func ButtonTapped(tag:Int){ 6 //省略 7}

これだとエラーが出てエラーの内容を調べるとselectorの引数指定が間違ってるということでした。

ViewController

1 Button.addTarget(self, action: #selector(ButtonTapped(tag:)), for: .touchUpInside) 2 self.view.addSubview(Button) 3} 4 5@objc func ButtonTapped(tag:Int){ 6 print(tag) 7} 8

こうするとエラーは消えましたがtagは設定したものではない数字がprintされました。
調べて以下のようにすると(一番最初のコードの全体像)tagが正しくprintされました。

ViewController

1 Button.addTarget(self, action: #selector(ButtonTapped(sender:)), for: .touchUpInside) 2 self.view.addSubview(Button) 3} 4 5@objc func ButtonTapped(sender:UIButton){ 6 print(sender.tag) 7} 8

##原理がわからない
ですが原理がわかりません。
for文の中でaddTargetを用いて処理をしています。
addTargetのselectorでButtonTapped(sender:)としていますが引数にButton(UIButton)を指定していないのになぜうまくいくのでしょうか?
普通であればButtonTapped(sender:Button)としなければうまくいかないと思います。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

addTargetのselectorでButtonTapped(sender:)としていますが
引数にButton(UIButton)を指定していないのになぜうまくいくのでしょうか?
普通であればButtonTapped(sender:Button)としなければうまくいかないと思います。

クロージャを使うような感覚でいると、うまくいかないと思うかもしれませんが、addTargetはクロージャを登録しているわけではないので問題ありません(セレクタは感覚としては関数名を文字列で渡している感じです)。

addTargetで指定できる関数の形式は3種類と決まっています。

https://developer.apple.com/documentation/uikit/uicontrol#1943645

Listing 1
Action method definitions
@IBAction func doSomething()

@IBAction func doSomething(sender: UIButton)
@IBAction func doSomething(sender: UIButton, forEvent event: UIEvent)

なので、これ以外の形式を自分で作ってセレクタで渡すことはできません。
これはそういう決まりです。

私も中の実装を見たわけではありませんので、推測レベルではありますが、
おそらくUIButtonはボタンがタップされたら、セレクタとして登録されているものの形式をチェックして、
例えばsenderにselfを付けてコールしているだけなんじゃないかと思います。

もともとクロージャが構文的に無い時代から存在する部分なので、こういう作りになっているだけかと思います。

投稿2020/03/11 06:15

takabosoft

総合スコア8356

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問