3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

UIButtonに隠しActionをつける方法

Posted at

はじめに

ただどう動くんだろう?って言うだけの話で実用性は皆無です:innocent:
なんか UIButton に謎のアクションを付けれたというお話です。

環境

  • Xcode 11.4
  • iPhone 11 Pro Max (13.4)

実装

  1. StoryboardでFirstViewControllerとSecondViewControllerを用意する
  2. FirstVCにボタンをのせる
  3. IBActionでボタンのアクションをFirstVCに紐付ける(tappedFirst(_ sender: Any)
  4. SecondVCにFirstVCのボタンをコピペする
  5. IBActionでボタンのアクションをSecondVCに紐付ける(tappedSecond(_ sender: Any)

こんな感じ

storyboard
final class FirstViewController: UIViewController {

    @IBAction private func tappedFirst(_ sender: Any) {
        print("First")
        let vc = storyboard?.instantiateViewController(identifier: "Second")
        navigationController?.pushViewController(vc!, animated: true)
    }
}

final class SecondViewController: UIViewController {

    @IBAction private func tappedSecond(_ sender: Any) {
        print("Second")
    }
}

現象

Storyboard で SecondVC のボタンを確認すると...
こうなる!

button_action

tappedFirst がついてる。シュミレータで SecondVC のボタンを押下してみると Second と print 表示される。(FirstVCの tappedFirst(_) が呼ばれたりはしない)unrecognized selector でクラッシュもしない:clap:

調査

下記のようにボタンのカスタムクラスを作り FirstVC と SecondVC のボタンに継承させる。

class CustomButton: UIButton {

    override func sendActions(for controlEvents: UIControl.Event) {
        print("sendActions")
        super.sendActions(for: controlEvents)
    }

    override func sendAction(_ action: Selector, to target: Any?, for event: UIEvent?) {
        print("sendAction")
        super.sendAction(action, to: target, for: event)
    }

    override func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool {
        print("beginTracking")
        return super.beginTracking(touch, with: event)
    }

    override func endTracking(_ touch: UITouch?, with event: UIEvent?) {
        print("endTracking")
        return super.endTracking(touch, with: event)
    }

    override func cancelTracking(with event: UIEvent?) {
        print("cancelTracking")
        super.cancelTracking(with: event)
    }

    override func addTarget(_ target: Any?, action: Selector, for controlEvents: UIControl.Event) {
        print("addTarget")
        super.addTarget(target, action: action, for: controlEvents)
    }
}

FirstVC表示時のログ

addTarget

FirstVCのボタン押下時のログ

beginTracking
endTracking
sendAction
First
addTarget

最後の addTarget は SecondVC 表示時のやつ

SecondVC表示時のログ

addTarget

アクションは2つあるけど1回しか呼ばれない:interrobang:

SecondVCのボタン押下時のログ

beginTracking
endTracking
sendAction
Second

調査結果

SecondVC のボタンの addTarget が一回しか呼ばれていないことからそもそも tappedFirst のアクションは追加されていないみたい:thinking:

button_action

Storyboardでアクションを付けたボタンを他画面からコピペすれば動作しない謎のアクションを付けることができる!これをすれば他の開発者を惑わすこともたやすいだろう:sunglasses:

さいごに

実装中に謎のアクションをみつけたので調べてみた結果です。活かせる場はあるだろうか:smiling_imp:

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?