Est-il possible d'utiliser Enum de Swift dans Obj-C?

145

J'essaye de convertir une partie de ma classe Obj-C en Swift. Et certaines autres classes Obj-C utilisent toujours enum dans cette classe convertie. J'ai cherché dans les documents préliminaires et je n'ai pas pu le trouver ou peut-être l'ai-je manqué. Existe-t-il un moyen d'utiliser Swift enum dans Obj-C Class? Ou un lien vers la documentation de ce numéro?

C'est ainsi que j'ai déclaré mon énumération dans mon ancien code Obj-C et mon nouveau code Swift.

mon ancien code Obj-C:

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

@interface SomeClass : NSObject

...

@end

mon nouveau code Swift:

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

class SomeClass: NSObject
{
    ...
}

Mise à jour: à partir des réponses. Cela ne peut pas être fait dans la version Swift antérieure à 1.2. Mais selon ce blog officiel de Swift . Dans Swift 1.2 qui a été publié avec XCode 6.3, vous pouvez utiliser Swift Enum dans Objective-C en ajoutant @objcdevantenum

myLifeasdog
la source
Il n'est pas vraiment nécessaire de modifier votre code existant. Pour l'interaction entre Swift et Objective-C, regardez les vidéos de la WWDC.
gnasher729
Je veux juste vérifier si mon projet fonctionne toujours s'il y aura une classe rapide dans mon projet à l'avenir, mais je ne peux pas déterminer quelle classe dois-je ajouter pour le tester. Donc, je convertis l'ancien à la place. Quoi qu'il en soit, merci pour votre aide.
myLifeasdog

Réponses:

226

À partir de la version 1.2 de Swift (Xcode 6.3), vous pouvez. Préfixez simplement la déclaration d'énumération avec@objc

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

Sans vergogne tiré du blog Swift

Remarque: cela ne fonctionnerait pas pour les énumérations String ou les énumérations avec les valeurs associées. Votre énumération devra être liée à Int


En Objective-C, cela ressemblerait à

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}
Daniel Galasko
la source
8
merci beaucoup de l'avoir signalé ... notez que dans objective-c si les valeurs d'énumération seront appelées BearBlack, BearGrizzlyet BearPolar!
nburk
1
Cela a du sens non? Surtout quand vous regardez comment c'est traduit de obj-c en swift .. @nburk
Daniel Galasko
1
Oui, cela fonctionne. Cependant, au moins dans mon cas, un attribut "public" a dû être ajouté à l'énumération pour qu'elle soit accessible du côté Objective-C du projet, comme ceci: "@objc public enum Bear: Int"
Pirkka Esko
Dommage que je ne vois aucune preuve que les valeurs associées Swift enum sont possibles.
wishful
2
@AJit pourquoi voudriez-vous faire ça? Ajoutez simplement l'énumération à son propre en-tête et importez-la dans l'en-tête de pont, sinon c'est exclusif à Swift
Daniel Galasko
31

Pour développer la réponse sélectionnée ...

Il est possible de partager des énumérations de style Swift entre Swift et Objective-C en utilisant NS_ENUM().

Ils ont juste besoin d'être définis dans un contexte Objective-C en utilisant NS_ENUM()et ils sont rendus disponibles en utilisant la notation Swift dot.

De l' utilisation de Swift avec Cocoa et Objective-C

Swift importe en tant qu'énumération Swift toute énumération de style C marquée par la NS_ENUMmacro. Cela signifie que les préfixes des noms de valeurs d'énumération sont tronqués lorsqu'ils sont importés dans Swift, qu'ils soient définis dans des frameworks système ou dans du code personnalisé.

Objectif c

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

Rapide

let cellStyle: UITableViewCellStyle = .Default
SirNod
la source
J'obtiens à la définition de fonction UITableViewCellStyle "n'est pas autorisée ici", qu'est-ce que je fais mal? Bien sûr, j'ai des noms différents non UITableViewCellStyle.
Cristi Băluță
1
Comme indiqué dans la réponse de M. Galasko ci-dessous, Swift 1.2 permet de définir les énumérations dans Swift et d'être disponibles dans Obj-c. Ce style de définition, à savoir NS_ENUM, fonctionne toujours dans Obj-c, mais à partir de la version 1.2 de Swift, vous pouvez utiliser l'une ou l'autre option.
SirNod
J'ai trouvé qu'il y a un problème avec les énumérations ObjC dans Swift: elles ne sont pas disponibles. Dans un fragment comme if let a = MyEnum(rawValue: 12345)où 12345 ne fait pas partie de cette énumération, le résultat n'est pas une énumération facultative mais une énumération invalide.
bio du
30

À partir du guide Utilisation de Swift avec Cocoa et Objective-C :

Une classe ou un protocole Swift doit être marqué avec l'attribut @objc pour être accessible et utilisable en Objective-C. [...]

Vous aurez accès à tout ce qui se trouve dans une classe ou un protocole marqué avec l'attribut @objc tant qu'il est compatible avec Objective-C. Cela exclut les fonctionnalités Swift uniquement telles que celles répertoriées ici:

Génériques Tuples / Enumérations définies dans Swift / Structures définies dans Swift / Fonctions de niveau supérieur définies dans Swift / Variables globales définies dans Swift / Typealiases définies dans Swift / Variadics de style Swift / Types imbriqués / Fonctions Curried

Donc, non, vous ne pouvez pas utiliser une énumération Swift dans une classe Objective-C.

hpique
la source
2
Y at-il un travail autour? Je veux dire si je crée une classe Swift et que j'ai absolument besoin d'une énumération. Comment puis-je rendre cette énumération utilisable également dans Objective-C?
Raul Lopez
4
@RaulLopezVillalpando Si vous savez que vous allez interagir avec Objective-C, vous devez déclarer l'énumération en Objective-C et laisser les deux langues la partager.
Gregory Higley
3
"Ouais, nous avons donc créé ce pont pour vous aider à faire la transition vers Swift, mais c'est inutile si vous voulez utiliser quelque chose de cool, comme Enums, Structs, Generics ... Donc, il y a ça ..."
Kevin R
22
CETTE RÉPONSE N'EST PLUS VALABLE !! depuis Xcode 6.3 / Swift 1.2, les énumérations Swift peuvent également être utilisées dans objective-c en utilisant @objccomme @DanielGalasko l'a souligné dans sa réponse ci-dessous !!!
nburk
9
Juste pour clarifier le commentaire ci-dessus, citant le texte actuel de la documentation de Swift 2.1 , "Enumérations définies dans Swift sans le type de valeur brute Int ". Donc, si votre énumération dans Swift est déclarée avec un type de valeur brute Int comme dans, @obj enum MyEnum: Intcela fonctionnera correctement sur les fichiers Objective-C comme mentionné précédemment. Si votre énumération est déclarée avec un autre type de valeur brute comme @obj enum MyOtherEnum: String, vous ne pourrez pas l'utiliser sur les fichiers Objective-C
jjramos
7

Swift 4.1, Xcode 9.4.1:

1) Swift enum doit être préfixé par @objcet être de Inttype:

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

2) Le nom Objective-C est le nom enum + le nom du cas, par exemple 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;
    }
}

Et, bien sûr, n'oubliez pas d'importer votre en-tête de pont Swift en tant que dernier élément de la liste d'importation du fichier Objective-C:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"
leanne
la source
pourquoi MyApp-Swift devrait-il être le dernier?
Paul
@PaulT. : a probablement à voir avec l'ordre de traitement. Essayez de le mettre ailleurs, et vous verrez que cela ne fonctionnera pas.
leanne le
J'ai vérifié, dans mon projet actuel, presque dans tous les fichiers, c'est à la fin de la section d'importation, mais dans plusieurs fichiers, ce n'est pas à la fin et le projet fonctionne. peut-être dans un nouveau Xcode cela fonctionne? Je ne peux pas le vérifier maintenant, car mon projet actuel prend des années à se compiler :), mais je vais le vérifier plus tard
Paul T.Le
2

Si vous préférez conserver les codes ObjC tels quels, vous pouvez ajouter un fichier d'en-tête d'assistance dans votre projet:

Swift2Objc_Helper.h

dans le fichier d'en-tête, ajoutez ce type d'énumération:

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

Il peut y avoir un autre endroit dans votre fichier .m pour effectuer une modification: pour inclure le fichier d'en-tête masqué:

#import "[YourProjectName]-Swift.h"

remplacez [YourProjectName] par le nom de votre projet. Ce fichier d'en-tête expose toutes les classes @objc définies par Swift, enums à ObjC.

Vous pouvez recevoir un message d'avertissement concernant la conversion implicite à partir du type d'énumération ... C'est OK.

En passant, vous pouvez utiliser ce fichier d'aide d'en-tête pour conserver certains codes ObjC tels que les constantes #define.

David.Chu.ca
la source
0

Si vous (comme moi) voulez vraiment utiliser les énumérations String, vous pouvez créer une interface spécialisée pour objective-c. Par exemple:

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))
}

Bien sûr, cela ne vous donnera pas la commodité de l'auto-complétion (sauf si vous définissez des constantes supplémentaires dans l'environnement objective-c).

Lukas Kalinski
la source
0

cela pourrait aider un peu plus

Énoncé du problème : - J'ai enum dans la classe swift, à laquelle j'accède depuis d'autres classes swift, et maintenant je dois y accéder depuis ma classe objective C.

Avant d'y accéder depuis la classe objective-c: -

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

Modifications pour y accéder depuis la classe objective c

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

et ajoutez une fonction pour lui transmettre la valeur

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

Après avoir recherché cela, j'ai continué à ne trouver que des réponses partielles, j'ai donc créé un exemple complet d'application Swift reliée à Objective C qui a des énumérations Swift utilisées par le code Objective C et des énumérations Objective C utilisées par le code Swift. C'est un projet Xcode simple que vous pouvez exécuter et expérimenter. Il a été écrit en utilisant Xcode 10.3 avec Swift 5.0

Exemple de projet

user3288724
la source
Je ne vois pas où votre projet utilise l'énumération rapide dans l'objectif C. De plus, la définition de l'énumération rapide enum SwAnimaln'a pas le premier@obj
oliolioli
0

Au cas où vous essayez d'observer une énumération qui ressemble à ceci:

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

cette solution de contournement m'a aidé.

Classe observable:

  • créer @objc dynamic var observable: String?
  • créez votre instance enum comme ceci:

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

Classe d'observateur:

  • créer private var _enumName: EnumName?
  • créer private let _instance = ObservableClass()
  • créer

    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)!
    })

Alors c'est ça. Désormais, chaque fois que vous modifiez le _enumNamedans la classe observable, une instance appropriée de la classe observable sera également immédiatement mise à jour.

Il s'agit bien sûr d'une implémentation simplifiée à l'extrême, mais elle devrait vous donner une idée de la façon d'observer les propriétés incompatibles avec KVO.

Gasper J.
la source