webentwicklung-frage-antwort-db.com.de

Wie gehe ich mit #selector () in Swift 4 mit @objc Inference Deprecation um?

Ich versuche, den Quellcode meines Projekts von Swift 3 in Swift 4 umzuwandeln. Eine Warnung, die Xcode gibt, betrifft meine Selektoren.

Zum Beispiel füge ich einer Schaltfläche ein Ziel hinzu, indem Sie eine reguläre Auswahl wie folgt verwenden:

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

Dies ist die Warnung, die es zeigt:

Das Argument von '#selector' bezieht sich auf die Instanzmethode 'myAction ()' in 'ViewController', die von der in @ Swift 4 veralteten '@objc'-Attributeinleitung abhängt

Fügen Sie '@objc' hinzu, um diese Instanzmethode für Objective-C verfügbar zu machen

Wenn Sie nun Fix in der Fehlermeldung drücken, wirkt sich dies auf meine Funktion aus:

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

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

Ich möchte nicht wirklich alle meine Funktionen umbenennen, um die Markierung @objc aufzunehmen. Ich gehe davon aus, dass dies nicht notwendig ist.

Wie schreibe ich die Auswahl um, um mit der Abwertung umzugehen?


Zugehörige Frage:

119
LinusGeffarth

Die Fehlerbehebung ist korrekt - es gibt nichts an der Auswahl, was Sie ändern können, um die Methode, auf die sie sich bezieht, für Objective-C verfügbar zu machen.

Der gesamte Grund für diese Warnung ist in erster Linie das Ergebnis von SE-016 . Vor Swift 4, internal oder höher Von Objective-C-kompatiblen Mitgliedern von NSObject, die Klassen erben, wurde angenommen, dass sie @objc sind und daher verfügbar sind in Objective-C, sodass sie mithilfe von Selektoren aufgerufen werden können (da die Obj-C-Laufzeit erforderlich ist, um die Methodenimplementierung für einen bestimmten Selektor nachzuschlagen).

In Swift 4 ist dies jedoch nicht mehr der Fall. Nur sehr spezifische Deklarationen werden jetzt als @objc bezeichnet, z. B. Überschreibungen von @objc Methoden, Implementierungen von @objc Protokollanforderungen und Deklarationen mit Attributen, die @objc implizieren, wie @IBOutlet.

Die Motivation dahinter ist, wie im Detail in dem oben verlinkten Vorschlag , zunächst zu verhindern, dass Methodenüberladungen in NSObject vererbenden Klassen aufgrund identischer Selektoren miteinander kollidieren. Zweitens wird die Binärgröße reduziert, indem keine Thunks für Member generiert werden müssen, die nicht mit Obj-C in Verbindung gebracht werden müssen, und drittens wird die Geschwindigkeit der dynamischen Verknüpfung verbessert.

Wenn Sie ein Mitglied Obj-C aussetzen möchten, müssen Sie es als @objc markieren, zum Beispiel:

class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()
        button.addTarget(self, action: #selector(foo), for: .touchUpInside)
    }

    @objc func foo() {
       // ... 
    }
}

(der Migrator sollte dies automatisch für Sie mit Selektoren tun, wenn die Option "Inferenz minimieren" ausgewählt ist)

Um eine Gruppe von Mitgliedern Obj-C auszusetzen, können Sie ein @objc extension verwenden:

@objc extension ViewController {

    // both exposed to Obj-C
    func foo() {}
    func bar() {}
}

Dadurch werden alle darin definierten Member für Obj-C verfügbar gemacht, und es wird ein Fehler für alle Member ausgegeben, die nicht für Obj-C verfügbar gemacht werden können (es sei denn, dies ist ausdrücklich als @nonobjc markiert).

Wenn Sie eine Klasse haben, in der Sie all Obj-C-kompatible Mitglieder benötigen, um mit Obj-C in Kontakt zu treten, können Sie die Klasse als @objcMembers markieren:

@objcMembers
class ViewController: UIViewController {
   // ...
}

Nun werden alle Mitglieder, von denen angenommen werden kann, dass sie @objc sind, Allerdings würde ich nicht empfehlen, dies zu tun, es sei denn, Sie wirklich benötigen alle Mitglieder, die mit Obj-C konfrontiert sind, angesichts der oben genannten Nachteile, Mitglieder unnötig exponiert zu haben.

151
Hamish

As Apple Official Documentation . Sie müssen @objc verwenden, um Ihre Selector-Methode aufzurufen.

In Objective-C ist ein Selektor ein Typ, der auf den Namen einer Objective-C-Methode verweist. In Swift werden Objective-C-Selektoren durch die Selector -Struktur dargestellt und können mit dem Ausdruck #selector Erstellt werden. Übergeben Sie den Namen der Methode, z. B. #selector(MyViewController.tappedButton(sender:)), um einen Selektor für eine Methode zu erstellen, die in Objective-C aufgerufen werden kann. Übergeben Sie zum Erstellen eines Selektors für die Objective-C-Getter- oder Setter-Methode einer Eigenschaft den Eigenschaftsnamen mit dem Präfix getter: Oder setter:, Z. B. #selector(getter: MyViewController.myButton).

16
Kiran Sarvaiya

Ab, ich denke, Swift 4.2, müssen Sie Ihrer Methode nur @IBAction zuweisen und Sie können diese dumme @objc-Anmerkung vermeiden

`` `

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


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

Wie bereits in anderen Antworten erwähnt, gibt es keine Möglichkeit, die Annotation @objc für Selektoren zu umgehen. 

Die im OP erwähnte Warnung kann jedoch durch folgende Schritte zum Schweigen gebracht werden: 

  1. Gehe zu Build-Einstellungen
  2. Suche nach Schlüsselwort @objc
  3. Setzen Sie den Wert von Swift 3 @objc interface auf Off.

unten sehen Sie einen Screenshot, der die oben genannten Schritte veranschaulicht: 

 Silencing the warning "Swift 3 @objc interface"

Hoffe das hilft

1
S1LENT WARRIOR

Wenn Sie Objective C-Member in Ihrem View-Controller benötigen, fügen Sie einfach@objcMembersoben im View-Controller hinzu. Sie können dies vermeiden, indem Sie IBAction in Ihren Code einfügen. 

`@IBAction func buttonAction () {

} `

Stellen Sie sicher, dass Sie diese Steckdose im Storyboard anschließen.

1
Renjish C