Wann soll @objc in Swift verwendet werden?

87

In Swift sehe ich einige Methoden wie:

@objc private func doubleTapGestureRecognized(recognizer: UITapGestureRecognizer)

Ich habe mich gefragt, wann ich @objc verwenden soll. Ich habe einige Dokumente gelesen, aber sie sagen, wenn Sie möchten, dass es in Objective-C aufgerufen werden kann, sollten Sie das Flag @objc hinzufügen

Dies ist jedoch eine private Funktion in Swift. Was macht der @obj?

Wingzero
quelle
1
gute Frage !!!
Erhan Demirci

Antworten:

66

privat bedeutet es nur in Swift sichtbar. Verwenden Sie also @objc, um in Objective-C sichtbar zu werden. Wenn Sie eine Funktion zum schnellen Auswählen einer privaten Funktion haben, ist diese erforderlich.

Das Attribut @objc stellt Ihre Swift-API in Objective-C und der Objective-C-Laufzeit zur Verfügung.

Siehe: https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html

Reming Hsu
quelle
1
also @objc private func doubleTapGestureRecognized, was ist der Punkt sowohl @objc und privat zu haben? Wollen Sie damit sagen, dass Objective-C-Klassen doubleTapGestureRecognized überschreiben können?
Wingzero
1
Ich denke, weil man in obj-c sowieso jede Methode überschreiben kann.
seltsamerweise
2
Ich bin mir nicht sicher, wie diese Antwort richtig ist und antworte auf sein Q. Die hier bereitgestellten Antworten befinden sich bereits in seinem Q selbst F ist "Dies ist eine private Funktion in Swift, was macht der \ @obj?"
KBJ
3
Links brechen. Besonders in der Apple-Dokumentation. Bitte ziehen Sie in Betracht, die Schlüsselelemente hier aus der Dokumentation zu extrahieren.
Levigroker
54

Eine weitere späte Antwort, aber keine der vorhandenen Antworten auf diese Frage beantwortet wirklich die Frage des OP: Warum zum Teufel müssten Sie @objcein privateKlassenmitglied verwenden, wenn @objces für die Interaktion mit Objective-C und dem betreffenden Mitglied vorhanden ist? ist privat, was bedeutet, dass selbst wenn Sie Objective-C-Code in Ihrem Projekt haben, es das Mitglied sowieso nicht sehen kann?

Der Grund dafür ist, dass, da viele der Frameworks in Objective-C geschrieben sind, manchmal Objective-C-Funktionen erforderlich sind, um mit bestimmten APIs zu interagieren.

Angenommen, ich möchte mich für eine Benachrichtigung registrieren über DistributedNotificationCenter:

DistributedNotificationCenter.default.addObserver(self,
                                                  selector: #selector(somethingHappened(_:)),
                                                  name: someNotification,
                                                  object: nil)

Damit dies funktioniert, müssen wir in der Lage sein, den Selektor für die somethingHappenedMethode zu erhalten. Selektoren sind jedoch ein Objective-C-Konzept. Wenn die Methode für Objective-C nicht sichtbar ist, verfügt sie nicht über einen Selektor. Daher kann , selbst wenn die Methode privat ist und nicht durch willkürlichen außerhalb Code aufgerufen werden soll, wird es eine müssen , @objcum für den DistributedNotificationCode, der in Objective-C geschrieben ist, nennt es über seine Wähler zu können.

Ein weiterer häufiger Fall, der @objcbenötigt wird, ist die Unterstützung der Schlüsselwertcodierung (KVC), insbesondere unter macOS, wo KVC und KVO zur Implementierung von Kakaobindungen verwendet werden. KVC wird wie viele andere Systeme in Cocoa in Objective-C implementiert, wodurch KVC-kompatible Eigenschaften für die Objective-C-Laufzeit verfügbar gemacht werden müssen. Manchmal ist es sinnvoll, dass KVC-konforme Eigenschaften privat sind. Ein Beispiel ist, wenn Sie eine Eigenschaft haben, die andere Eigenschaften beeinflusst:

@objc private dynamic var originalProperty: String

@objc private static let keyPathsForValuesAffectingDependentProperty: Set<String> = [
    #keyPath(originalProperty)
]
@objc public var dependentProperty: String { return changeItSomehow(self.originalProperty) }

In diesem Fall ist unsere tatsächlich gespeicherten Eigenschaft privat, aber die abhängige Eigenschaft, die wir tun , um außerhalb Code aufzudecken, muss seine Benachrichtigungen senden , wenn das Privateigentum aktualisiert. Durch Markieren der Privateigenschaft als @objckönnen wir dies leicht tun, indem wir eine KVC-Abhängigkeit einrichten. Andernfalls müssten wir Code schreiben, um die Benachrichtigungen in den Privateigentumern willSetund didSetHandlern manuell zu senden . Darüber hinaus muss die statische Eigenschaft, die das von dependentPropertyabhängige KVC-System informiert originalProperty, für Objective-C verfügbar gemacht werden, damit das KVC-System es finden und aufrufen kann. Für Kunden unseres Codes ist es jedoch nicht relevant.

Außerdem kann ein Ansichtscontroller in einer macOS-App, der Steuerelemente in seiner Ansicht mithilfe von Cocoa Bindings als Implementierungsdetail aktualisiert, bestimmte private Eigenschaften KVC-kompatibel machen, um diese Steuerelemente an sie zu binden.

Wie Sie sehen, kann es vorkommen, dass eine Methode oder Eigenschaft für Objective-C verfügbar gemacht werden muss, um mit den Frameworks zu interagieren, ohne dass dies für Clients Ihres Codes unbedingt sichtbar sein muss.

Charles Srstka
quelle
25

@objc / dynamic

Dies dient der Kompatibilität: Sobald Sie Ihre Swift-Datei / Ihren Swift-Code in ein Objective-C-basiertes Projekt importiert haben.

Verwenden Sie diese Option, wenn auf Ihre Eigenschaft / Methode über Objective-C-Code oder -Klasse zugegriffen werden soll.

Meistens passiert dies, wenn Sie eine Swift-Klasse der Objective-C-Basisklasse unterklassifizieren.

Eine Swift-Klasse oder ein Swift-Protokoll muss mit dem Attribut @objc gekennzeichnet sein , damit sie in Objective-C zugänglich und verwendbar ist. Dieses Attribut teilt dem Compiler mit, dass auf diesen Swift-Code von Objective-C aus zugegriffen werden kann. Wenn Ihre Swift-Klasse ein Nachkomme einer Objective-C-Klasse ist, fügt der Compiler automatisch das @ objc-Attribut für Sie hinzu.

Hier Apple-Dokumentation, die über sagt @objc.

Verwenden von Swift aus Objective-C

Kompatibilität der Sprachinteroperabilität

Links aktualisiert:
Anscheinend wurden die Links von Apple aktualisiert.

0yeoj
quelle
11

@objc ist ein Klassenattribut, das Sie verwenden

@objc public class MyClass

Die Methoden der Klasse werden für Objective C-Klassen verfügbar gemacht, sodass Sie sie nur verwenden, wenn Ihre Klasse öffentliche Funktionen enthält

Fraser
quelle
7

Eine späte Antwort, aber dieses @objcVerhalten ändert sich ab Swift 4 (das in Xcode 9 veröffentlicht wurde, das vor 10 Tagen veröffentlicht wurde) geringfügig.

In Swift 4 werden einige Inferenzfälle von @objcentfernt. Dies bedeutet nur in einigen zusätzlichen Fällen, dass der @objcHeader in Swift 4 nicht abgeleitet wurde, bevor er vom Swift-Compiler abgeleitet wurde.

Lesen Sie mehr im Swift Evolution-Vorschlag zu dieser Änderung

Wie bereits erwähnt, besteht im Allgemeinen @objcdarin, bestimmte Methoden der Objective-C-Laufzeit auszusetzen, die Teil der Swift-Interoperabilität der Sprache ist.

BHendricks
quelle
1
Dies sollte der Grund sein, warum nach dem Update auf Swift 4 einige Variablen von ObjC aus nicht zugänglich sind, oder? Mit Swift 3.X war es nicht nötig hinzuzufügen@objc
rgkobashi
oh ok, es ist immer gut, mit jemand anderem zu sprechen, danke!
Rgkobashi
1

@objcsetzt eine Erklärung aus Objective-C runtime. Schauen wir uns die #selectorFunktion von Swift an, um eine Objective-C-Laufzeit zu verwenden. In diesem Fall können Sie Ihren Swift definieren @objc private func[Mehr]

So verwenden Sie Swifts Funktionen aus Objective-C:

  1. Swifts Klasse sollte von erweitert werden NSObject
  2. Mark Swifts:

    ein. Nur @objcMembers Klasse - um alle public Konstruktoren , Felder und Methoden verfügbar zu machen . Es gilt auch für Unterklassen

    b. @objc Klasse / Aufzählung / Protokoll (außer Struktur ) [Benannter Typ]

    • @objc Klasse (optional) - um einen Standard verfügbar zu machen public init() . Oder @objc(<custom_name>)um einen benutzerdefinierten Namen für die Klasse einzurichten.
    • @objc Konstruktoren , Felder und Methoden - um sie selektiv verfügbar zu machen

Swifts Methode wird bei der nächsten Benennung verfügbar sein:

<swiftName>With<firstArgument>:<secondArgument>:

Beispielsweise:

public func printHelloWorld(arg1: String, arg2:String)
//is reached through: 
[someObject printHelloWorldWithArg1: arg2:];

[ @objcund dynamic]

yoAlex5
quelle