[解決済み] Swiftの#selector構文による「ambiguous use of」コンパイルエラーの解決方法とは?
質問
[ 注意 この質問はもともとSwift 2.2のもとで作成されました。それはSwift 4のために修正され、2つの重要な言語の変更を含んでいます:最初のメソッドパラメータの外部はもはや自動的に抑制されず、セレクタは明示的にObjective-Cに公開しなければなりません]。
私のクラスにこれらの2つのメソッドがあるとします。
@objc func test() {}
@objc func test(_ sender:AnyObject?) {}
では、Swift 2.2の新しい
#selector
構文を使って
最初の
に対応するセレクタを作ることができます。
func test()
. どうすればいいのでしょうか?これを試すと
let selector = #selector(test) // error
... というエラーが表示されます。
test()
." しかし、もし私がこう言うなら。
let selector = #selector(test(_:)) // ok, but...
...エラーは消えますが、今度は 間違ったメソッド を参照しています。 で をパラメータとするもの。を参照したいのですが がなく を参照したいのですが、パラメータがありません。私はそれを行うにはどうすればよいですか?
[注意:この例は人工的なものではありません。NSObjectはObjective-Cの両方の
copy
と
copy:
インスタンスメソッド、Swift
copy()
と
copy(sender:AnyObject?)
というように、実生活でも簡単に問題が発生します] 。
どのように解決するのか?
[ 注意 この回答はもともとSwift 2.2のもとで作成されました。それはSwift 4のために修正され、2つの重要な言語の変更を含んでいます:最初のメソッドパラメータの外部は、もはや自動的に抑制されず、セレクタは明示的にObjective-Cに公開されなければなりません].
この問題を回避するために キャスティング を正しいメソッドシグネチャにキャストすることで回避できます。
let selector = #selector(test as () -> Void)
(しかし、私の考えでは、このようなことをする必要はないはずです。私はこの状況をバグとみなし、Swiftの関数参照の構文が不十分であることを明らかにしています。私はバグレポートを提出しましたが、無駄でした)。
ただ、要約すると、新しい
#selector
の構文があります。
この構文の目的は、セレクタをリテラル文字列として与えたときに発生する、あまりにも一般的なランタイムクラッシュ(通常は "認識されないセレクタ" )を防ぐことにあります。
#selector()
は
関数参照
を取ると、コンパイラはその関数が本当に存在するかどうかをチェックし、その参照をObjective-Cのセレクタに解決してくれます。したがって、容易に間違いを犯すことはできません。
(
EDITです。
なるほど、できるんですね。完全なヘタレで、ターゲットを
#selector
. コンパイラはあなたを止めないので、昔と同じようにクラッシュします。はぁ...)
関数参照は3つの形式のいずれかで現れることができます。
-
関数参照は ベアネーム を指定します。関数が曖昧でなければ、これで十分です。したがって、例えば
@objc func test(_ sender:AnyObject?) {} func makeSelector() { let selector = #selector(test) }
は1つだけです。
test
メソッドは一つしかないので、この#selector
はパラメータを取るにもかかわらず、それを参照し#selector
がパラメータに言及していないにもかかわらず、を参照しています。解決された Objective-C セレクタは、舞台裏では、まだ正しく "test:"
(となります(パラメータを示すコロン付き)。 -
の残りの部分と一緒に関数の名前を指定します。 シグネチャ . 例えば
func test() {} func test(_ sender:AnyObject?) {} func makeSelector() { let selector = #selector(test(_:)) }
私たちは、2つの
test
メソッドがあるので、区別する必要があります。test(_:)
は 第二 に解決されます。 -
関数の名前にシグネチャの残りを加えたもの、または省いたもの。 キャスト を表示します。 タイプ を表示します。このように
@objc func test(_ integer:Int) {} @nonobjc func test(_ string:String) {} func makeSelector() { let selector1 = #selector(test as (Int) -> Void) // or: let selector2 = #selector(test(_:) as (Int) -> Void) }
ここでは オーバーロード
test(_:)
. Objective-Cはオーバーロードを許可していないので、どちらか一方しか公開されず、セレクタを形成できるのは は が公開される。セレクタはObjective-Cの機能であるからだ。しかし、私たちは まだ は、Swiftに関する限り曖昧さをなくし、キャストはそれを行います。(上記の回答の根拠として使われる-私の意見では誤用-のは、この言語的特徴です)。
また、関数がどのクラスにあるのかを伝えることで、Swiftが関数参照を解決するのを助けなければならないかもしれません。
-
クラスがこのクラスと同じか、このクラスからスーパークラス連鎖の上にある場合、さらなる解決は通常必要ありません(上記の例で示されるように); オプションとして、次のように言うことができます
self
というように、ドット・ノートを使って(例えば#selector(self.test)
というように、状況によってはそうしなければならないかもしれません。 -
そうでない場合は インスタンス への参照を、ドット表記で使用します。
self.mp
は MPMusicPlayerController です)。let pause = UIBarButtonItem(barButtonSystemItem: .pause, target: self.mp, action: #selector(self.mp.pause))
...または、ファイル名として クラス のように、ドットノテーションで指定することもできます。
class ClassA : NSObject { @objc func test() {} } class ClassB { func makeSelector() { let selector = #selector(ClassA.test) } }
(と言っているように見えるので、不思議な記法に思えます)。
test
がインスタンスメソッドではなくクラスメソッドであると言っているように見えるからです。しかし、それでもセレクタに正しく解決されるでしょう。)
関連
-
[解決済み] Swiftでindexとelementでループを反復させる方法
-
[解決済み] Swift 3で現在の日付を取得する?[クローズド]
-
[解決済み] Swiftのリバースレンジ
-
[解決済み] ビルド入力ファイルが見つかりません」Swift 4.2、Xcode 10.0
-
[解決済み] Swift: switch ケースでオプションの値に対するテストを行う
-
[解決済み] SwiftUIのForEachでインデックスを取得する
-
[解決済み] カスタムイニシャライザを持つSwift enumはrawValueイニシャライザを失う
-
[解決済み] NSDateを使用して曜日を取得する
-
[解決済み] Swiftによる文字列中の部分文字列のインデックス
-
[解決済み] Swiftでセレクタに引数を渡す
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] selector' の引数が '@objc' メソッド、プロパティ、またはイニシャライザを参照していない
-
[解決済み] Swiftの@selector()?
-
[解決済み] Swift 1.2では、宣言は「final」と「dynamic」の両方にはなり得ないというエラーがある
-
[解決済み] Swift: PREPROCESSORフラグ(`#if DEBUG`など)を使ってAPIキーを実装する方法とは?
-
[解決済み] SwiftUIで条件付きでビューを使用する
-
[解決済み] ボタンを無効化する
-
[解決済み] SwiftUIのForEachでインデックスを取得する
-
[解決済み] swift で文字列から数字以外の文字を削除する
-
[解決済み] SwiftのAnyObjectとAny
-
[解決済み] swift 3.0 Data to String?