Ist es möglich, Swift's Enum in Obj-C zu verwenden?

144

Ich versuche, einen Teil meiner Obj-C-Klasse in Swift umzuwandeln. Und einige andere Obj-C-Klassen verwenden immer noch Enum in dieser konvertierten Klasse. Ich habe in den Pre-Release-Dokumenten gesucht und konnte es nicht finden oder habe es verpasst. Gibt es eine Möglichkeit, Swift enum in der Obj-C-Klasse zu verwenden? Oder ein Link zum Dokument dieser Ausgabe?

So habe ich meine Aufzählung in meinem alten Obj-C-Code und meinem neuen Swift-Code deklariert.

mein alter Obj-C Code:

typedef NS_ENUM(NSInteger, SomeEnum)
{
    SomeEnumA,
    SomeEnumB,
    SomeEnumC
};

@interface SomeClass : NSObject

...

@end

Mein neuer Swift Code:

enum SomeEnum: NSInteger
{
    case A
    case B
    case C
};

class SomeClass: NSObject
{
    ...
}

Update: Aus den Antworten. Dies ist in einer älteren Swift-Version als 1.2 nicht möglich. Aber laut diesem offiziellen Swift Blog . In Swift 1.2 , dass mit XCode 6.3 freigegeben entlang, können Sie Swift Enum verwenden in Objective-C durch Zugabe @objcvorenum

myLifeasdog
quelle
Es ist nicht wirklich notwendig, Ihren vorhandenen Code zu ändern. Sehen Sie sich für die Interaktion zwischen Swift und Objective-C die WWDC-Videos an.
Gnasher729
Ich möchte nur überprüfen, ob mein Projekt noch funktioniert, ob es in Zukunft eine schnelle Klasse in meinem Projekt geben wird, aber ich kann nicht herausfinden, welche Klasse ich hinzufügen soll, um es zu testen. Also konvertiere ich stattdessen die alte. Trotzdem danke für deine Hilfe.
myLifeasdog

Antworten:

225

Ab Swift Version 1.2 (Xcode 6.3) können Sie. Stellen Sie der Enum-Deklaration einfach das Präfix vor@objc

@objc enum Bear: Int {
    case Black, Grizzly, Polar
}

Schamlos aus dem Swift Blog entnommen

Hinweis: Dies funktioniert nicht für String-Aufzählungen oder Aufzählungen mit zugehörigen Werten. Ihre Aufzählung muss gebunden sein


In Objective-C würde dies so aussehen

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}
Daniel Galasko
quelle
8
Vielen Dank für den Hinweis ... Beachten Sie, dass in Ziel-c die Aufzählungswerte aufgerufen werden BearBlack, BearGrizzlyund BearPolar!
nburk
1
Das macht doch nein Sinn? Besonders wenn man sich ansieht, wie es von obj-c in schnell übersetzt wird. @Nburk
Daniel Galasko
1
Ja, das funktioniert. Zumindest in meinem Fall musste der Aufzählung jedoch ein "öffentliches" Attribut hinzugefügt werden, damit es auf der Objective-C-Seite des Projekts zugänglich ist, wie folgt: "@objc public enum Bear: Int"
Pirkka Esko
Schade, dass ich keine Beweise dafür sehe, dass mit Swift enum verbundene Werte möglich sind. Wunschdenken
finneycanhelp
2
@AJit warum willst du das machen?
Fügen
31

So erweitern Sie die ausgewählte Antwort ...

Es ist möglich, Swift-Enums zwischen Swift und Objective-C zu teilen NS_ENUM().

Sie müssen nur in einem Objective-C-Kontext mit definiert werden NS_ENUM()und werden mit der Swift-Punktnotation verfügbar gemacht.

Aus der Verwendung von Swift mit Kakao und Objective-C

Swift importiert als Swift-Aufzählung jede mit dem NS_ENUMMakro markierte C-Aufzählung . Dies bedeutet, dass die Präfixe für Aufzählungswertnamen beim Import in Swift abgeschnitten werden, unabhängig davon, ob sie in Systemframeworks oder in benutzerdefiniertem Code definiert sind.

Ziel c

typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
   UITableViewCellStyleDefault,
   UITableViewCellStyleValue1,
   UITableViewCellStyleValue2,
   UITableViewCellStyleSubtitle
};

Schnell

let cellStyle: UITableViewCellStyle = .Default
SirNod
quelle
Ich erhalte beim UITableViewCellStyle "Funktionsdefinition ist hier nicht erlaubt", was mache ich falsch? Natürlich habe ich verschiedene Namen, nicht UITableViewCellStyle.
Cristi Băluță
1
Wie in der Antwort von Herrn Galasko unten erwähnt, ermöglicht Swift 1.2, dass Aufzählungen in Swift definiert werden und in Obj-c verfügbar sind. Dieser Definitionsstil, nämlich NS_ENUM, funktioniert immer noch in Obj-c, aber ab Swift Version 1.2 können Sie beide Optionen verwenden.
SirNod
Ich habe festgestellt, dass es in Swift ein Problem mit ObjC-Aufzählungen gibt: Sie sind nicht ausfallbar. In einem Fragment wie if let a = MyEnum(rawValue: 12345)12345, das nicht Teil dieser Aufzählung ist, ist das Ergebnis keine optionale, sondern eine ungültige Aufzählung.
Bio
30

Aus dem Handbuch Verwenden von Swift mit Kakao und Objective-C :

Eine Swift-Klasse oder ein Swift-Protokoll muss mit dem Attribut @objc gekennzeichnet sein, damit sie in Objective-C zugänglich und verwendbar ist. [...]

Sie haben Zugriff auf alles innerhalb einer Klasse oder eines Protokolls, das mit dem Attribut @objc gekennzeichnet ist, sofern es mit Objective-C kompatibel ist. Dies schließt nur Swift-Funktionen wie die hier aufgeführten aus:

Generische Tupel / Aufzählungen definiert in Swift / Strukturen definiert in Swift / Funktionen der obersten Ebene definiert in Swift / Globale Variablen definiert in Swift / Typealiasen definiert in Swift / Swift-Stil Variadics / Verschachtelte Typen / Curried-Funktionen

Nein, Sie können keine Swift-Enumeration in einer Objective-C-Klasse verwenden.

hpique
quelle
2
Gibt es eine Problemumgehung? Ich meine, wenn ich eine Swift-Klasse erstelle und unbedingt eine Aufzählung brauche. Wie kann ich diese Aufzählung auch für Objective-C verwenden?
Raul Lopez
4
@RaulLopezVillalpando Wenn Sie wissen, dass Sie mit Objective-C zusammenarbeiten werden, sollten Sie die Aufzählung in Objective-C deklarieren und beide Sprachen gemeinsam nutzen lassen.
Gregory Higley
3
"Ja, also haben wir diese Brücke gemacht, um Ihnen den Übergang zu Swift zu erleichtern, aber es ist nutzlos, wenn Sie etwas Cooles verwenden möchten, wie Enums, Structs, Generics ... Also gibt es das ..."
Kevin R
22
DIESE ANTWORT IST NICHT MEHR GÜLTIG !! Seit Xcode 6.3 / Swift 1.2 können Swift-Enums auch innerhalb von Objective-C verwendet werden, @objcwie in seiner Antwort unten unter @DanielGalasko angegeben !!!
nburk
9
Um den obigen Kommentar zu verdeutlichen, zitieren Sie den aktuellen Text in der Dokumentation ab Swift 2.1 , "In Swift definierte Aufzählungen ohne Int-Rohwerttyp ". Wenn Ihre Aufzählung in Swift mit einem Int-Rohwerttyp wie in deklariert ist, @obj enum MyEnum: Intfunktioniert dies wie zuvor erwähnt für Objective-C-Dateien einwandfrei. Wenn Ihre Aufzählung mit einem anderen @obj enum MyOtherEnum: String
Rohwerttyp
7

Swift 4.1, Xcode 9.4.1:

1) Swift enum muss vorangestellt werden @objcund vom IntTyp:

// in .swift file:
@objc enum CalendarPermission: Int {
    case authorized
    case denied
    case restricted
    case undetermined
}

2) Ziel-C-Name ist Aufzählungsname + Fallname, z CalendarPermissionAuthorized.

// in .m file:
// point to something that returns the enum type (`CalendarPermission` here)
CalendarPermission calPermission = ...;

// use the enum values with their adjusted names
switch (calPermission) {
    case CalendarPermissionAuthorized:
    {
        // code here
        break;
    }
    case CalendarPermissionDenied:
    case CalendarPermissionRestricted:
    {
        // code here
        break;
    }
    case CalendarPermissionUndetermined:
    {
        // code here
        break;
    }
}

Denken Sie natürlich daran, Ihren Swift-Bridging-Header als letztes Element in der Importliste der Objective-C-Datei zu importieren:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"
Leanne
quelle
Warum sollte MyApp-Swift der letzte sein?
Paul T.
@ PaulT. : hat wahrscheinlich mit der Reihenfolge der Verarbeitung zu tun. Versuchen Sie es woanders zu platzieren, und Sie werden sehen, dass es nicht funktioniert.
Leanne
Ich habe überprüft, dass es in meinem aktuellen Projekt fast in allen Dateien am Ende des Importabschnitts ist, aber in einigen Dateien nicht am Ende und das Projekt funktioniert. kann in einem neuen Xcode sein, dass es funktioniert? Ich kann es jetzt nicht überprüfen, da das Kompilieren meines aktuellen Projekts ewig dauert :), aber ich werde es später überprüfen
Paul T.
2

Wenn Sie die ObjC-Codes lieber unverändert lassen möchten, können Sie Ihrem Projekt eine Hilfskopfdatei hinzufügen:

Swift2Objc_Helper.h

Fügen Sie in der Header-Datei diesen Aufzählungstyp hinzu:

typedef NS_ENUM(NSInteger, SomeEnum4ObjC)
{
   SomeEnumA,
   SomeEnumB
};

Möglicherweise befindet sich in Ihrer .m-Datei ein anderer Ort, an dem Sie Änderungen vornehmen können: um die versteckte Header-Datei einzuschließen:

#import "[YourProjectName]-Swift.h"

Ersetzen Sie [YourProjectName] durch Ihren Projektnamen. Diese Header-Datei macht alle von Swift definierten @ objc-Klassen und Aufzählungen für ObjC verfügbar.

Möglicherweise erhalten Sie eine Warnmeldung zur impliziten Konvertierung vom Aufzählungstyp ... Es ist in Ordnung.

Übrigens können Sie diese Header-Hilfsdatei verwenden, um einige ObjC-Codes wie #define-Konstanten beizubehalten.

David.Chu.ca
quelle
0

Wenn Sie (wie ich) wirklich String-Aufzählungen verwenden möchten, können Sie eine spezielle Schnittstelle für Objective-C erstellen. Beispielsweise:

enum Icon: String {
    case HelpIcon
    case StarIcon
    ...
}

// Make use of string enum when available:
public func addIcon(icon: Icon) {
    ...
}

// Fall back on strings when string enum not available (objective-c):
public func addIcon(iconName:String) {
    addIcon(Icon(rawValue: iconName))
}

Dies bietet Ihnen natürlich nicht die Möglichkeit, automatisch zu vervollständigen (es sei denn, Sie definieren zusätzliche Konstanten in der Objective-C-Umgebung).

Lukas Kalinski
quelle
0

das könnte ein bisschen mehr helfen

Problemstellung : - Ich habe eine Aufzählung in der Swift-Klasse, auf die ich von anderen Swift-Klassen aus zugreife, und jetzt muss ich von meiner Zielklasse C darauf zugreifen.

Bevor Sie von der Ziel-C-Klasse darauf zugreifen: -

enum NTCType   {
    case RETRYNOW
    case RETRYAFTER
}
 var viewType: NTCType? 

Änderungen für den Zugriff von der Zielklasse c

@objc  enum NTCType :Int  {
    case RETRYNOW
    case RETRYAFTER
}

und fügen Sie eine Funktion hinzu, um sie an den Wert weiterzugeben

  @objc  func setNtc(view:NTCType)  {
        self.viewType = view; // assign value to the variable
    }
Anurag Bhakuni
quelle
0

Nachdem ich dies untersucht hatte, fand ich immer wieder nur teilweise Antworten. Daher erstellte ich ein vollständiges Beispiel für eine Swift-App, die mit Objective C verbunden ist und Swift-Aufzählungen enthält, die von Objective C-Code und Objective C-Aufzählungen verwendet werden, die von Swift-Code verwendet werden. Es ist ein einfaches Xcode-Projekt, mit dem Sie experimentieren können. Es wurde mit Xcode 10.3 mit Swift 5.0 geschrieben

Beispielprojekt

user3288724
quelle
Ich sehe nicht, wo Ihr Projekt die rasche Enum in Objective C. Auch die Definition des schnellen ENUM nutzt enum SwAnimalfehlt die führende@obj
oliolioli
0

Falls Sie versuchen, eine Aufzählung zu beobachten, die folgendermaßen aussieht:

enum EnumName: String {
    case one = "One"
    case two = "Two"
}

Diese Problemumgehung hat mir geholfen.

Beobachtbare Klasse:

  • erstellen @objc dynamic var observable: String?
  • Erstellen Sie Ihre Enum-Instanz folgendermaßen:

    private var _enumName: EnumName? {
        didSet {
            observable = _enumName!.rawValue
        }
    }

Beobachterklasse:

  • erstellen private var _enumName: EnumName?
  • erstellen private let _instance = ObservableClass()
  • erstellen

    private var _enumObserver: NSKeyValueObservation = _instance.observe(\.observable, options: .new, changeHandler: { [weak self] (_, value) in
        guard let newValue = value.newValue else { return }
        self?._enumName = EnumName(rawValue: period)!
    })

Dann ist es soweit. Jedes Mal, wenn Sie die _enumNamein der beobachtbaren Klasse ändern , wird auch eine entsprechende Instanz in der Beobachterklasse sofort aktualisiert.

Dies ist natürlich eine stark vereinfachte Implementierung, sollte Ihnen jedoch eine Vorstellung davon geben, wie Sie KVO-inkompatible Eigenschaften beobachten können.

Gasper J.
quelle