Swift 4 で #selector() を使用した @objc 推論の非推奨化に対処するにはどうすればよいでしょうか? 質問する

Swift 4 で #selector() を使用した @objc 推論の非推奨化に対処するにはどうすればよいでしょうか? 質問する

プロジェクトのソース コードを 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 に公開する必要があります。

おすすめ記事