È possibile utilizzare Swift's Enum in Obj-C?


145

Sto cercando di convertire parte della mia classe Obj-C in Swift. E alcune altre classi Obj-C usano ancora enum in quella classe convertita. Ho cercato in Pre-Release Docs e non sono riuscito a trovarlo o forse mi sono perso. C'è un modo per usare Swift enum nella classe Obj-C? O un link al documento di questo problema?

È così che ho dichiarato il mio enum nel mio vecchio codice Obj-C e nel nuovo codice Swift.

il mio vecchio codice Obj-C:

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

@interface SomeClass : NSObject

...

@end

il mio nuovo codice Swift:

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

class SomeClass: NSObject
{
    ...
}

Aggiornamento: dalle risposte. Non può essere fatto nella versione precedente di Swift di 1.2. Ma secondo questo blog ufficiale di Swift . In Swift 1.2 rilasciato insieme a XCode 6.3, puoi usare Swift Enum in Objective-C aggiungendo @objcdavanti aenum


Non è davvero necessario modificare il codice esistente. Per l'interazione tra Swift e Objective-C, guarda i video del WWDC.
gnasher729,

Voglio solo verificare se il mio progetto funziona ancora se ci sarà una classe rapida nel mio progetto in futuro, ma non riesco a capire quale classe dovrei aggiungere per testarlo. Quindi, converto invece quello vecchio. Ad ogni modo, grazie per il tuo aiuto.
myLifeasdog,

Risposte:


226

A partire dalla versione 1.2 di Swift (Xcode 6.3) è possibile. Basta aggiungere il prefisso alla dichiarazione enum con@objc

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

Spudoratamente tratto dal Blog Swift

Nota: questo non funzionerebbe con enumerazioni String o enumerazioni con valori associati. Il tuo enum dovrà essere associato a Int


In Objective-C questo sarebbe simile

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}

8
grazie mille per averlo sottolineato ... nota che in obiettivo-c i valori di enum saranno chiamati BearBlack, BearGrizzlye BearPolar!
nburk,

1
Questo ha senso no? Soprattutto quando guardi come viene tradotto da obj-c in rapido .. @nburk
Daniel Galasko,

1
Sì, funziona. Tuttavia, almeno nel mio caso è stato necessario aggiungere un elenco "pubblico" all'enumerazione per renderlo accessibile dal lato Obiettivo-C del progetto, in questo modo: "@objc public enum Bear: Int"
Pirkka Esko

Peccato che non vedo alcuna prova che i valori associati all'enumerazione Swift siano possibili. pio desiderio
finneycanhelp il

2
@Ajit perché vorresti farlo? Basta aggiungere l'enum alla propria intestazione e importarlo nell'intestazione del ponte, altrimenti è esclusivo di Swift
Daniel Galasko il

31

Per espandere la risposta selezionata ...

È possibile condividere gli enum di stile Swift tra Swift e Objective-C usando NS_ENUM().

Devono solo essere definiti in un contesto Objective-C usando NS_ENUM()e sono resi disponibili usando la notazione a punti Swift.

Dal Utilizzando Swift con cacao e Objective-C

Swift importa come enumerazione Swift qualsiasi enumerazione in stile C contrassegnata con la NS_ENUMmacro. Ciò significa che i prefissi ai nomi dei valori di enumerazione vengono troncati quando vengono importati in Swift, siano essi definiti in framework di sistema o in codice personalizzato.

Objective-C

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

veloce

let cellStyle: UITableViewCellStyle = .Default

Ottengo dalla UITableViewCellStyle "la definizione della funzione non è consentita qui", cosa sto facendo di sbagliato? Ovviamente ho nomi diversi non UITableViewCellStyle.
Cristi Băluță,

1
Come indicato nella risposta di Galasko di seguito, Swift 1.2 consente di definire gli enum in Swift e di renderli disponibili in Obj-c. Questo stile di definizione, vale a dire NS_ENUM, funziona ancora in Obj-c, ma a partire dalla versione 1.2 di Swift è possibile utilizzare entrambe le opzioni.
SirNod,

Ho scoperto che c'è un problema con gli enumerati ObjC in Swift: non sono disponibili. In un frammento come if let a = MyEnum(rawValue: 12345)dove 12345 non fa parte di quell'enum, il risultato non è un enum opzionale ma un enum non valido.
bio

30

Dalla guida Uso di Swift con Cocoa e Objective-C :

Una classe o un protocollo Swift deve essere contrassegnato con l'attributo @objc per essere accessibile e utilizzabile in Objective-C. [...]

Avrai accesso a qualsiasi cosa all'interno di una classe o di un protocollo contrassegnato con l'attributo @objc purché sia ​​compatibile con Objective-C. Ciò esclude le funzionalità solo di Swift come quelle elencate qui:

Generiche Tuple / Enumerazioni definite in Swift / Strutture definite in Swift / Funzioni di livello superiore definite in Swift / Variabili globali definite in Swift / Tipologie definite in Swift / Variazioni di tipo Swift / Tipi nidificati / Funzioni di Curry

Quindi no, non puoi usare un'enumerazione Swift in una classe Objective-C.


2
C'è una soluzione? Voglio dire se creo una classe Swift e ho assolutamente bisogno di un enum. Come posso rendere quell'enum utilizzabile anche in Objective-C?
Raul Lopez,

4
@RaulLopezVillalpando Se sai che interagirai con Objective-C, allora dovresti dichiarare l'enumerazione in Objective-C e lasciare che entrambe le lingue lo condividano.
Gregory Higley,

3
"Sì, quindi abbiamo creato questo ponte per aiutarti a passare a Swift, ma è inutile se vuoi usare qualcosa di interessante, come Enums, Structs, Generics ... Quindi c'è quello ..."
Kevin R

22
QUESTA RISPOSTA NON È PIÙ VALIDA !! da Xcode 6.3 / Swift 1.2, le enumerazioni Swift possono anche essere usate all'interno di @objcgoal -c usando come indicato da @DanielGalasko nella sua risposta qui sotto !!!
nburk,

9
Giusto per chiarire il commento sopra, citando il testo corrente sulla documentazione a partire da Swift 2.1 , "Enumerazioni definite in Swift senza tipo di valore grezzo Int ". Quindi, se la tua enum in Swift viene dichiarata con un tipo di valore grezzo Int come in @obj enum MyEnum: Int, funzionerà bene sui file Objective-C come menzionato prima. Se il tuo enum è dichiarato con un altro tipo di valore grezzo come @obj enum MyOtherEnum: String, non sarai in grado di usarlo su file Objective-C
jjramos

7

Swift 4.1, Xcode 9.4.1:

1) Swift enum deve essere preceduto da @objced essere di Inttipo:

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

2) Il nome obiettivo-C è il nome enum + il nome del caso, ad esempio 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;
    }
}

E, naturalmente, ricorda di importare la tua intestazione ponte Swift come ultimo elemento nell'elenco di importazione del file Objective-C:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"

perché MyApp-Swift dovrebbe essere l'ultimo?
Paul T.

@PaulT. : probabilmente ha a che fare con l'ordine di elaborazione. Prova a metterlo altrove e vedrai che non funzionerà.
leanne

Ho controllato, nel mio progetto attuale quasi in tutti i file è alla fine della sezione di importazione, ma in diversi file non è alla fine e il progetto funziona. potrebbe essere in un nuovo Xcode che funziona? Non riesco a controllarlo ora, perché il mio progetto attuale impiega anni per essere compilato :), ma lo controllerò più tardi
Paul T.

2

Se preferisci mantenere i codici ObjC così come sono, puoi aggiungere un file di intestazione helper nel tuo progetto:

Swift2Objc_Helper.h

nel file di intestazione aggiungi questo tipo di enum:

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

Potrebbe esserci un altro posto nel tuo file .m per apportare una modifica: per includere il file di intestazione nascosto:

#import "[YourProjectName]-Swift.h"

sostituisci [YourProjectName] con il nome del tuo progetto. Questo file di intestazione espone tutte le classi @objc definite da Swift, enum a ObjC.

È possibile che venga visualizzato un messaggio di avviso sulla conversione implicita dal tipo di enumerazione ... Va bene.

A proposito, potresti usare questo file helper dell'intestazione per conservare alcuni codici ObjC come le costanti #define.


0

Se tu (come me) volessi davvero usare enumerazioni String, potresti creare un'interfaccia specializzata per goal-c. Per esempio:

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

Naturalmente, questo non ti darà la comodità del completamento automatico (a meno che tu non definisca costanti aggiuntive nell'ambiente obiettivo-c).


0

questo potrebbe aiutare un po 'di più

Dichiarazione problema : - Ho enum in classe swift, a cui accedo da altre classi swift, e ora ho bisogno di accedervi dal mio uno della classe C obiettivo.

Prima di accedervi dalla classe obiettivo-c: -

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

Modifiche per accedervi dalla classe c obiettiva

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

e aggiungi una funzione per passarla sul valore

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

0

Dopo aver studiato questo, ho continuato a trovare solo risposte parziali, quindi ho creato un intero esempio di un'app Swift collegata all'obiettivo C che ha enumerazioni Swift utilizzate dal codice Objective C e enumerazioni Objective C utilizzate dal codice Swift. È un semplice progetto Xcode che puoi eseguire e sperimentare. È stato scritto usando Xcode 10.3 con Swift 5.0

Progetto di esempio


Non vedo dove il tuo progetto utilizza l'enumerazione rapida nell'Obiettivo C. Anche la definizione dell'enumerazione rapida enum SwAnimal manca del leader@obj
oliolioli

0

Nel caso in cui stai cercando di osservare un enum che assomiglia a questo:

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

questa soluzione alternativa mi ha aiutato.

Classe osservabile:

  • creare @objc dynamic var observable: String?
  • crea la tua istanza enum in questo modo:

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

Classe di osservatori:

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

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

Grazie. Ora ogni volta che cambi la _enumNamenella classe osservabile, anche un'istanza appropriata sulla classe dell'osservatore verrà immediatamente aggiornata.

Questa è ovviamente un'implementazione semplificata, ma dovrebbe darti un'idea di come osservare le proprietà incompatibili con KVO.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.