Swift 4の#selector()で@objc推論の非推奨に対処するにはどうすればよいですか?


131

プロジェクトのソースコードをSwift 3からSwift 4に変換しようとしています。Xcodeから出される警告の1つは、セレクターに関するものです。

たとえば、次のような通常のセレクターを使用してボタンにターゲットを追加します。

button.addTarget(self, action: #selector(self.myAction), for: .touchUpInside)

これはそれが示す警告です:

「#selector」の引数は、Swift 4で廃止された「@objc」属性推論に依存する「ViewController」のインスタンスメソッド「myAction()」を参照しています

'@objc'を追加して、このインスタンスメソッドをObjective-Cに公開します。

今、Fixエラーメッセージを打つことは私の関数に対してこれを行います:

// before
func myAction() { /* ... */ }

// after
@objc func myAction() { /* ... */ }

@objcマークを含むようにすべての関数の名前を変更したくないので、その必要はありません。

非推奨に対処するためにセレクターをどのように書き換えますか?


関連する質問:


3
それらをマーキングいいえ、@objc であるのObj-Cにそれらを公開するので、セレクタで使用するために、今必要。
Hamish

3
したがって、非推奨の部分は、パブリックアクセス関数を@objc?それは少し面倒ですが、私は通常これらの関数をプライベートにし、@objcとにかくそれをマークするように要求します。
コナー

2
変更の詳細については、SE-0160を参照してください。別の方法として@objcMembers、すべてのObj-C互換メンバーをObj-Cに公開するために、指定されたクラスをマークすることもできますが、クラス全体を実際に公開する必要がない限り、私はアドバイスしません。
Hamish

3
@LinusGeffarth提案で述べたように、バイナリのサイズが不必要に大きくなり、動的リンクに時間がかかる可能性があります。Obj-Cから使用される特定の物について具体的に意味することは、追加された明快さのためにそれほど面倒ではないと私は本当に思いません。
ハミッシュ

1
試してみましたが、機能していません。
LinusGeffarth 2017

回答:


156

修正は正しい–セレクターが参照するメソッドをObjective-Cに公開するために変更できるセレクターについては何もありません。

この警告の最初の理由は、SE-0160の結果です。Swift 4以前internalは、NSObject継承クラスのObjective-C互換メンバーは、@objcとれ、Objective-Cに公開されていたため、セレクターを使用してそれらを呼び出すことができました(メソッドを検索するためにObj-Cランタイムが必要になるため)特定のセレクターの実装)。

ただし、Swift 4では、これは当てはまりません。非常に具体的な宣言のみが@objc、たとえば、@objcメソッドの、@objcプロトコル要件の実装@objc、などの暗黙の属性を持つ宣言など、ようになりました@IBOutlet

詳細は、この背後にある動機、 上記のリンクされた提案れているように、は、最初にメソッドのオーバーロードを防ぐNSObject継承するクラスのが同一のセレクターがあるために互いに衝突するのことです。2つ目は、Obj-Cに公開する必要のないメンバーのサンクを生成する必要がないため、バイナリサイズの削減に役立ち、3つ目は動的リンクの速度が向上します。

メンバーを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に曝露され、すべてのメンバーが必要不必要にさらさ有する部材の上記の欠点を考えると、。


2
コードを最新の構文に変換するときに、Xcodeが自動的にそれを行わないのはなぜですか?
LinusGeffarth 2017

1
私は、不思議です@IBAction自動的にも@objc?今まではそうではありませんでしたが、当然のことです。編集:nvm、提案は明らかに@IBActionメソッドが十分であることを述べてい@objcます
スルタン

8
何もわかりません。今までObjective-Cコードはありませんでした。ボタンにターゲットを追加する純粋なSwiftの方法はありませんか?またはセレクターを使用しますか?私のコードがこの属性でいじられたくありません。UIButtonがNSObject / Obj-c-thingから派生しているためですか?
Sti

11
@Stiつまり、「ボタンにターゲットを追加する純粋なSwiftの方法はありませんか?それともセレクタを使用しますか?」–いいえ、セレクタを使用してメソッドにディスパッチする「純粋なSwift」の方法はありません。特定のセレクターを呼び出すためにメソッド実装をルックアップするために、Obj-Cランタイムに依存しています。Swiftランタイムにはその機能がありません。
ハミッシュ2017年

12
男のセレクターはめちゃくちゃです。彼らはそれを台無しにして他のすべての迅速な更新のようです。メソッドの純粋な迅速なオートコンプリートセレクターを用意できないのはなぜですか。コードをとても醜く見せます。
John Riselvato 2017年

16

アップル公式ドキュメントとして。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)


これから理解できることは、Objective-Cから呼び出すかどうかに関係なく、場合によってはfuncの先頭に@objcを追加する必要があるということです。私は何年もObj-Cを使用してきたSwiftを学んでいるだけです
SundialSoft '

10

現時点では、Swift 4.2だと思います。@ IBActionをメソッドに割り当てるだけで、このばかげた@objcアノテーションを回避できます。

「」

let tap  =  UITapGestureRecognizer(target: self, action: #selector(self.cancel))


@IBAction func cancel()
{
    self.dismiss(animated: true, completion: nil)
}

1
これはまた、この関数を接続できることをインターフェイスビルダーに通知しますが、これは必要な機能ではない場合があります。@objcと同じことも行います。
Josh Paradroid、

2

他の回答ですでに述べたように、回避する方法はありません @objc、セレクター注釈。

しかし、OPで言及された警告は、次の手順を実行することによって沈黙させることができます。

  1. に行く ビルド設定に
  2. キーワードで検索 @objcを
  3. Swift 3 @objcインターフェースの値をOff

以下は、上記の手順を示すスクリーンショットです。

警告「Swift 3 @objcインターフェース」を停止する

お役に立てれば


これは全体像であなたのプロジェクトにどのように影響しますか?
Zonily Jame、2018

1
* .ipaまたは* .xarchiveのサイズとビルド時間はどうですか?
Zonily Jame 2018

@ZonilyJameビルド時間に気づかなかったが、IPAサイズに影響はなかった
S1LENT WARRIOR

これは、Appleのガイドラインに従ってSwift 4.0以降のバージョンを使用している場合に使用できる推奨値ではありません。このヘルプを
mac

1
この答えを更新するには、Xcode 11で値を「デフォルト」に設定します。警告を完全に削除するには、プロジェクトとターゲットの両方に値を設定することが重要です。
トミーC.

2

ビューコントローラーで目的のcメンバーが必要な場合は、ビューコントローラーの上部に@objcMembersを追加するだけ です。そして、コードにIBActionを追加することでこれを回避できます。

@IBAction func buttonAction() {

}

ストーリーボードでこのコンセントを接続してください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.