プロジェクトのソース コードを Swift 3 から Swift 4 に変換しようとしています。Xcode からセレクターに関する警告が出ています。
たとえば、次のような通常のセレクターを使用してボタンにターゲットを追加します。
button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)
表示される警告は次のとおりです:
'#selector' の引数は、Swift 4 で非推奨となった '@objc' 属性推論に依存する 'ViewController' のインスタンス メソッド 'myAction()' を参照しています。
このインスタンスメソッドをObjective-Cに公開するには、「@objc」を追加します。
ここで、Fix
エラー メッセージをクリックすると、関数に対して次の処理が実行されます。
// before
func myAction() { /* ... */ }
// after
@objc func myAction() { /* ... */ }
すべての関数の名前を変更してマークを含めるつもりはありません@objc
が、それは必要ないと考えています。
廃止に対処するためにセレクターを書き換えるにはどうすればよいでしょうか?
関連する質問:
ベストアンサー1
修正は正しいです。セレクターについては、参照するメソッドを Objective-C に公開するために変更できるものはありません。
そもそもこの警告の理由は、SE-0160Swift 4 以前、internal
またはそれ以降のバージョンでは、継承クラスの Objective-C 互換メンバーは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() {
// ...
}
}
(「推論を最小化する」オプションを選択して実行する場合、移行ツールはセレクターを使用してこれを自動的に実行します)
メンバーのグループを Obj-C に公開するには、以下を使用できます@objc extension
。
@objc extension ViewController {
// both exposed to Obj-C
func foo() {}
func bar() {}
}
これにより、その中で定義されているすべてのメンバーが Obj-C に公開され、Obj-C に公開できないメンバーについてはエラーが発生します (明示的に としてマークされていない限り@nonobjc
)。
必要なクラスがある場合全てObj-C 互換のメンバーを Obj-C に公開するには、クラスを次のようにマークできます@objcMembers
。
@objcMembers
class ViewController: UIViewController {
// ...
}
これで、推測できるすべてのメンバー@objc
が対象になります。ただし、次の場合を除き、これを行うことはお勧めしません。本当に不必要にメンバーを公開することによる上記の欠点を考慮すると、すべてのメンバーを Obj-C に公開する必要があります。