web-dev-qa-db-ja.com

Swiftでセレクターを使用する適切な方法

プログラムでビューを作成し、アクションがUIControlEvents.TouchUpInsideイベントに応答するように関数を追加しています。

button.addTarget(self, action: action, forControlEvents: 
UIControlEvents.TouchUpInside)

したがって、ドキュメントに移動することで、このアクションをセレクターとして追加しました。

#selector(ViewController.onRegularClick)

次に、XCodeは以下についての不満を示します。

#selectorの引数がObjective-Cに公開されていないメソッドを参照しています

だから私はハンドラー関数を設定する必要があります:

@objc func onRegularClick(sender: UIButton)

誰かが私をドキュメントに導くことによってこのnoobを正しい方向に置くことができますか、または簡単な説明をしてください:

  1. なぜ関数名Stringをアクションに渡せないのですか?
  2. Swift方法に従ってこれを実装する適切な方法は?セレクタークラスを使用して?
  3. @objcキーワードを渡す必要がある理由と、それが関数に与える影響

ありがとうございました!

14
josetapadas
  1. なぜ関数名Stringをアクションに渡せないのですか?

セレクターに文字列を使用することは非推奨になり、_"methodName"_の代わりに#selector(methodName)と書く必要があります。 methodName()メソッドが存在しない場合は、コンパイルエラーが発生します。これは、コンパイル時に除去されるバグの別のクラス全体です。これは文字列では不可能でした。

  1. Swift方法に従ってこれを実装する適切な方法は?セレクタークラスを使用して?

あなたはそれを正しい方法で行いました:

button.addTarget(self, action: #selector(ClassName.methodName(_:)), forControlEvents: UIControlEvents.TouchUpInside)

  1. @objcキーワードを渡す必要がある理由と、それが関数に与える影響

Swiftの通常のアプローチは、コンパイル時にメソッドの呼び出しとメソッドの本体をバインドすることです(CやC++のように)。ObjectiveCは実行時にそれを行います。したがって、Objective CではいくつかのことができますSwift-たとえば、実行時にメソッドの実装を交換することが可能です(これはメソッドスウィズリングと呼ばれます)。CocoaはObjective Cのアプローチで動作するように設計されており、これが理由です。 SwiftメソッドはObjectiveCのようなスタイルでコンパイルする必要があることをコンパイラに通知する必要があります。クラスがNSObjectを継承する場合、@ objcキーワードがなくてもObjCのようなスタイルでコンパイルされます。

14
Avt
  1. まあ、それは進化と呼ばれています
  2. メソッドに引数がある場合、セレクターを次のように宣言する必要があります。

    _let selector = #selector(YourClass.selector(_:))
    _

    セレクターが呼び出し元と同じクラスにある場合は、#selector(selector(_:))のみを入力できます。 __:_は、1つのパラメーターを受け入れることを意味します。そのため、より多くのパラメーターを受け入れる場合は、_(_:, _:)_などのようにする必要があります。

  3. _@objc_が必要なのは、関数がプライベートとして宣言されているか、オブジェクトがNSObjectから継承されていない場合のみです。

8
Luca D'Alberti

Swift3.の場合は、以下のコードのようにします。

        yourButton.addTarget(self, action: #selector(yourButtonPressed), for: .touchUpInside)

およびyourButtonPressedメソッド

@IBAction func yourButtonPressed(sender:UIButton) {
    // Do your code here
}
2

1:現在は可能ですが、非推奨の警告が作成されます。 Swift 3では、これはエラーになるので、すぐに修正する必要があります。これは、関数が実際に存在し、それが実行時に動的に解決できる有効なObjective C関数。

2:次のようにしてください:

button.addTarget(self, action: #selector(MyViewControllerClass.buttonPressed(_:)), forControlEvents: UIControlEvents.TouchUpInside)

3:通常、@ objc属性を使用する必要はありません。私はあなたのクラスViewControllerが(何らかの理由で)UIViewControllerから派生していないと思います。 UIViewControllerから派生する場合は、関数でセレクターを呼び出すために必要なObjC動作も継承します。

2
Darko

みんなの答えは完璧ですが、私にはもっと良いアプローチがあります。あなたがそれを好きになることを願っています。

fileprivate extension Selector {
    static let buttonTapped = 
        #selector(ViewController.buttonTapped(_:))
}
...
button.addTarget(self, action: .buttonTapped, for: .touchUpInside)

このファイル内のプライベートは、ファイル内でのみタップされたボタンを表示するのに役立ちます。

0
singh.jitendra

プログラム的に

button.addTarget(self, action: #selector(returnAction), for: .touchUpInside)

// MARK: - Action
 @objc private func returnAction(sender: UIButton) {
        print(sender.tag)            
}
0
Wasim