私は自分のプロジェクトのソースコードをSwift 3からSwift 4に変換しようとしています。Xcodeから警告が出ます。
たとえば、次のような通常のセレクタを使用してボタンにターゲットを追加します。
button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)
これはそれが示す警告です:
'#selector'の引数は、 'ViewController'内のインスタンスメソッド 'myAction()'を参照します。これは '@objc'属性推論に依存しており、Swift 4では廃止予定です。
このインスタンスメソッドをObjective-Cに公開するには、 '@ objc'を追加します。
さて、エラーメッセージのFix
を押すことは私の関数にこれをします:
// before
func myAction() { /* ... */ }
// after
@objc func myAction() { /* ... */ }
私は本当に@objc
マークを含むように私のすべての関数の名前を変更したくありません、そして、私はそれが必要ではないと思います。
非推奨に対処するためにどうやってセレクタを書き直すのですか?
関連質問:
修正は正しいです。セレクタが参照するメソッドをObjective-Cに公開するために変更できるセレクタについては何もありません。
そもそもこの警告の全体的な理由は、 SE-016 の結果です。 Swift 4より前は、internal
以上のObjective-C互換クラスのNSObject
継承クラスは@objc
であると推測されたため、Objective-Cに公開されていたため、それらはセレクターを使用して呼び出されます(特定のセレクターのメソッド実装を検索するにはObj-Cランタイムが必要です)。
ただし、Swift 4では、これは当てはまりません。 @objc
メソッドのオーバーライド、@objc
プロトコル要件の実装、@objc
を暗示する属性を持つ宣言など、非常に具体的な宣言のみが@objc
であると推測されるようになりました。 @IBOutlet
。
上記のリンクされた提案で のように、この背後にある動機は、最初にNSObject
継承クラスのメソッドのオーバーロードが同一のセレクターを持つために互いに衝突するのを防ぐことです。第二に、Obj-Cにさらされる必要のないメンバーのサンクを生成する必要がないため、バイナリサイズを削減でき、第三に、動的リンクの速度が向上します。
メンバーをObj-Cに公開する場合は、次のように@objc
としてマークする必要があります。
class ViewController: UIViewController {
@IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: #selector(foo), for: .touchUpInside)
}
@objc func foo() {
// ...
}
}
(「minimise inference」オプションが選択された状態で実行されている場合、マイグレーターはセレクターでこれを自動的に行う必要があります)
メンバーのグループをObj-Cに公開するには、@objc extension
を使用できます。
@objc extension ViewController {
// both exposed to Obj-C
func foo() {}
func bar() {}
}
これにより、定義されているすべてのメンバーがObj-Cに公開され、Obj-Cに公開できないメンバーにエラーが発生します(明示的に@nonobjc
とマークされている場合を除く)。
all Obj-Cと互換性のあるメンバーをObj-Cに公開する必要があるクラスがある場合、クラスを@objcMembers
としてマークできます。
@objcMembers
class ViewController: UIViewController {
// ...
}
これで、@objc
であると推測できるすべてのメンバーがそうなります。ただし、メンバーが不必要に公開されるという上記の欠点を考えると、本当に Obj-Cに公開されているすべてのメンバーが必要でない限り、これを行うことはお勧めしません。
As Apple Official Documentation として。 Selectorメソッドを呼び出すには@objcを使用する必要があります。
Objective-Cでは、セレクタはObjective-Cメソッドの名前を参照する型です。 Swiftでは、Objective-Cのセレクタは
Selector
構造体で表され、#selector
式を使用して構築できます。 Objective-Cから呼び出せるメソッドのセレクタを作成するには、#selector(MyViewController.tappedButton(sender:))
のようにメソッドの名前を渡します。プロパティのObjective-Cのgetterメソッドまたはsetterメソッドのセレクタを作成するには、#selector(getter: MyViewController.myButton)
のように、getter:
またはsetter:
というラベルを前に付けたプロパティ名を渡します。
Swift 4.2では、@ IBActionをメソッドに代入するだけでよいので、この愚かな@objcアノテーションを避けることができます。
`` `
let tap = UITapGestureRecognizer(target: self, action: #selector(self.cancel))
@IBAction func cancel()
{
self.dismiss(animated: true, completion: nil)
}
ビューコントローラにObjective Cのメンバが必要な場合は、ビューの上部に@ objcMembersを追加するだけです。コントローラ。コードにIBActionを追加することでこれを回避できます。
@IBAction func buttonAction() {
}
ストーリーボードでこのコンセントを必ず接続してください。