1. ホーム
  2. swift

[解決済み] Swiftの@selector()?

2022-03-14 20:08:35

質問

を作成しようとしています。 NSTimerSwift が、ちょっと困っています。

NSTimer(timeInterval: 1, target: self, selector: test(), userInfo: nil, repeats: true)

test() は同じクラスの関数です。


エディターでエラーが発生します。

init' のオーバーロードで、提供されたものを受け入れるものが見つかりませんでした。 引数

を変更すると selector: test() から selector: nil を実行すると、エラーが消えます。

試してみました。

  • selector: test()
  • selector: test
  • selector: Selector(test())

しかし、何も機能せず、参考文献にも解決策が見当たりません。

解決方法は?

スウィフト そのもの Objective-Cではセレクタを使用するいくつかのデザインパターンは、Swiftでは異なる動作をします。(例えば、プロトコルタイプでオプションのチェインを使用するか、または is / as の代わりに respondsToSelector: の代わりに、可能な限りクロージャを使用します。 performSelector: 型/メモリ安全性を高めるためです)。

しかし、タイマやターゲット/アクション・パターンなど、セレクタを使用するObjCベースの重要なAPIがまだ多数あります。Swift では Selector 型は、これらを扱うためのものです。(Swiftは自動的にObjCの SEL 型を使用します)。

Swift 2.2 (Xcode 7.3) 以降 (Swift 3 / Xcode 8 および Swift 4 / Xcode 9 を含む) の場合。

を構築することができます。 Selector を使って、Swift の関数型から #selector の式で表されます。

let timer = Timer(timeInterval: 1, target: object,
                  selector: #selector(MyClass.test),
                  userInfo: nil, repeats: false)
button.addTarget(object, action: #selector(MyClass.buttonTapped),
                 for: .touchUpInside)
view.perform(#selector(UIView.insertSubview(_:aboveSubview:)),
             with: button, with: otherButton)

この方法の素晴らしい点は?関数参照はSwiftコンパイラによってチェックされるので #selector 式は、実際に存在し、セレクタとして使用することができるクラスとメソッドのペアでのみ使用できます (下記の "Selector availability" を参照)。また、関数の参照は、以下のように必要なだけ具体的にすることができます。 Swift 2.2+の関数型命名のルールである .

(これは、実際にはObjCの @selector() ディレクティブは、コンパイラの -Wundeclared-selector のチェックは、指定されたセレクタが存在するかどうかだけを確認します。に渡す Swift の関数参照は #selector は、存在、クラス内のメンバーシップ、およびタイプシグネチャをチェックします)。

に渡す関数参照には、さらにいくつかの注意点があります。 #selector という式があります。

  • 同じベース名を持つ複数の関数は、パラメータラベルで区別するために、前述の 関数参照用の構文 (例 insertSubview(_:at:)insertSubview(_:aboveSubview:) ). しかし、関数にパラメータがない場合、それを曖昧にする唯一の方法は as を関数の型シグネチャと一緒にキャストします(例. foo as () -> ()foo(_:) ).
  • Swift 3.0+では、プロパティゲッター/セッターのペアのための特別な構文があります。例えば var foo: Int を使用することができます。 #selector(getter: MyClass.foo) または #selector(setter: MyClass.foo) .

一般的な注意事項

以下のようなケース #selector が機能しない、ネーミングも。 セレクタを作るための関数参照がない場合があります(例えば、ObjCランタイムに動的に登録されたメソッドの場合)。そのような場合は Selector を文字列から作成します。 Selector("dynamicMethod:") - ただし、コンパイラの有効性チェックは失われます。その際、ObjCの命名規則に従う必要があり、コロン( : ) を各パラメータに指定します。

セレクタの有無。 セレクタで参照されるメソッドは、ObjCランタイムに公開されている必要があります。Swift 4 では、ObjC に公開されるすべてのメソッドは、その宣言の前に @objc 属性があります。(以前のバージョンでは、この属性は場合によっては無料で取得できましたが、現在は明示的に宣言する必要があります)。

次のことを忘れないでください。 private シンボルはランタイムには公開されません。あなたのメソッドは少なくとも internal を可視化します。

キーパスです。 これらはセレクタと関連していますが、全く同じではありません。Swift 3 では、これらのための特別な構文もあります: 例. chris.valueForKeyPath(#keyPath(Person.friends.firstName)) . 参照 SE-0062 をご覧ください。さらにさらに KeyPath Swift 4 のスタッフ そのため、適切な場合はセレクタの代わりにKeyPathベースのAPIを使用していることを確認してください。

セレクタについては、以下のページで詳しく説明しています。 Objective-CのAPIと連動する CocoaとObjective-CでSwiftを使用する .

Swift 2.2以前。 Selector に準拠しています。 StringLiteralConvertible そのため、セレクタを受け取るAPIに裸の文字列が渡される古いコードを見つけることができるかもしれません。Xcode で "Convert to Current Swift Syntax" を実行して、以下のようなものを取得したいと思うでしょう。 #selector .