¿Es posible usar Swift's Enum en Obj-C?

144

Estoy tratando de convertir parte de mi clase de Obj-C a Swift. Y algunas otras clases de Obj-C todavía usan enum en esa clase convertida. Busqué en los documentos de prelanzamiento y no pude encontrarlo o tal vez lo perdí. ¿Hay alguna manera de usar Swift enum en Obj-C Class? ¿O un enlace al documento de este número?

Así es como declaró mi enumeración en mi antiguo código Obj-C y el nuevo código Swift.

mi antiguo código Obj-C:

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

@interface SomeClass : NSObject

...

@end

mi nuevo código Swift:

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

class SomeClass: NSObject
{
    ...
}

Actualización: de las respuestas. No se puede hacer en la versión anterior de Swift que la 1.2. Pero según este blog oficial de Swift . En Swift 1.2 que se lanzó junto con XCode 6.3, puede usar Swift Enum en Objective-C agregando @objcdelante deenum

myLifeasdog
fuente
Realmente no hay ninguna necesidad de cambiar su código existente. Para la interacción entre Swift y Objective-C, mira los videos de WWDC.
gnasher729
Solo quiero verificar si mi proyecto aún funciona si habrá una clase rápida en mi proyecto en el futuro, pero no puedo entender qué clase debo agregar para probarlo. Entonces, convierto el viejo en su lugar. De todos modos, gracias por tu ayuda.
myLifeasdog

Respuestas:

226

A partir de la versión 1.2 de Swift (Xcode 6.3) puede hacerlo. Simplemente prefija la declaración enum con@objc

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

Descaradamente tomado del Blog Swift

Nota: Esto no funcionaría para las enumeraciones de cadena o enumeraciones con valores asociados. Su enumeración tendrá que estar vinculada internamente


En Objective-C esto se vería así

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}
Daniel Galasko
fuente
8
muchas gracias por señalarlo ... tenga en cuenta que en el objetivo-c, aunque los valores enum serán llamados BearBlack, BearGrizzlyy BearPolar!
nburk
1
Eso tiene sentido no? Especialmente cuando miras cómo se traduce de obj-c a swift .. @nburk
Daniel Galasko
1
Si, esto funciona. Sin embargo, al menos en mi caso, se tuvo que agregar un atributo "público" a la enumeración para que fuera accesible en el lado del Objetivo-C del proyecto, así: "@objc public enum Bear: Int"
Pirkka Esko
Lástima que no veo ninguna evidencia de que los valores asociados a Swift enum sean posibles. ilusiones
finneycanhelp 03 de
2
@AJit, ¿por qué quieres hacer eso? Simplemente agregue la enumeración a su propio encabezado e impórtelo en el encabezado de puente, de lo contrario es exclusivo de Swift
Daniel Galasko
31

Para ampliar la respuesta seleccionada ...

Es posible compartir enumeraciones de estilo Swift entre Swift y Objective-C usando NS_ENUM().

Solo necesitan definirse en un contexto Objective-C usando NS_ENUM()y están disponibles usando la notación de puntos Swift.

Del uso de Swift con cacao y Objective-C

Swift importa como una enumeración Swift cualquier enumeración de estilo C marcada con la NS_ENUMmacro. Esto significa que los prefijos de los nombres de valores de enumeración se truncan cuando se importan a Swift, ya sea que estén definidos en los marcos del sistema o en el código personalizado.

C objetivo

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

Rápido

let cellStyle: UITableViewCellStyle = .Default
Señor
fuente
Llego a UITableViewCellStyle "la definición de función no está permitida aquí", ¿qué estoy haciendo mal? Por supuesto, tengo diferentes nombres, no UITableViewCellStyle.
Cristi Băluță
1
Como se señala en la respuesta del Sr. Galasko a continuación, Swift 1.2 permite que las enumeraciones se definan en Swift y estén disponibles en Obj-c. Este estilo de definición, es decir NS_ENUM, todavía funciona en Obj-c, pero a partir de la versión 1.2 de Swift puede usar cualquiera de las opciones.
SirNod
Descubrí que hay un problema con las enumeraciones de ObjC en Swift: no están disponibles. En un fragmento como if let a = MyEnum(rawValue: 12345)donde 12345 no es parte de esa enumeración, el resultado no es opcional sino una enumeración no válida.
bio
30

De la guía Uso de Swift con cacao y Objective-C :

Una clase o protocolo Swift debe estar marcado con el atributo @objc para que sea accesible y utilizable en Objective-C. [...]

Tendrá acceso a cualquier cosa dentro de una clase o protocolo que esté marcado con el atributo @objc siempre que sea compatible con Objective-C. Esto excluye las funciones solo de Swift, como las que se enumeran aquí:

Tuplas genéricas / Enumeraciones definidas en Swift / Estructuras definidas en Swift / Funciones de nivel superior definidas en Swift / Variables globales definidas en Swift / Typealiases definidas en Swift / Variadas de estilo Swift / Tipos anidados / Funciones curry

Entonces, no, no puedes usar una enumeración Swift en una clase Objective-C.

hpique
fuente
2
¿Hay alguna solución? Quiero decir, si creo una clase Swift y realmente necesito una enumeración. ¿Cómo puedo hacer que esa enumeración también se pueda usar en Objective-C?
Raúl López
44
@RaulLopezVillalpando Si sabe que va a interactuar con Objective-C, debe declarar la enumeración en Objective-C y dejar que ambos lenguajes la compartan.
Gregory Higley
3
"Sí, así que hicimos este puente para ayudarte a hacer la transición a Swift, pero es inútil si quieres usar algo genial, como Enums, Structs, Generics ... Entonces ahí está eso ..."
Kevin R
22
¡ESTA RESPUESTA NO ES MÁS VÁLIDA! desde Xcode 6.3 / Swift 1.2, las enumeraciones de Swift también se pueden usar dentro del objetivo-c usando @objccomo @DanielGalasko señaló en su respuesta a continuación.
nburk
9
Solo para aclarar el comentario anterior, citando el texto actual en la documentación de Swift 2.1 , "Enumeraciones definidas en Swift sin tipo de valor bruto Int ". Por lo tanto, si su enumeración en Swift se declara con un tipo de valor sin procesar Int, ya @obj enum MyEnum: Intque funcionará bien en archivos Objective-C como se mencionó anteriormente. Si su enumeración se declara con otro tipo de valor sin @obj enum MyOtherEnum: Stringformato como , no podrá usarla en archivos Objective-C
jjramos el
7

Swift 4.1, Xcode 9.4.1:

1) Swift enum debe tener el prefijo @objcy ser Inttype:

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

2) El nombre de Objective-C es enum name + case name, por ejemplo 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;
    }
}

Y, por supuesto, recuerde importar su encabezado de puente Swift como último elemento en la lista de importación del archivo Objective-C:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"
leanne
fuente
¿Por qué debería ser MyApp-Swift el último?
Paul T.
@PaulT. : probablemente tiene que ver con el orden de procesamiento. Intenta colocarlo en otro lugar y verás que no funcionará.
Leanne
Verifiqué, en mi proyecto actual, casi en todos los archivos está al final de la sección de importación, pero en varios archivos no está al final y el proyecto funciona. puede estar en un nuevo Xcode que funciona? No puedo verificarlo ahora, porque mi proyecto actual tarda años en compilarse :), pero lo revisaré más tarde
Paul T.
2

Si prefiere mantener los códigos ObjC tal como están, puede agregar un archivo de encabezado auxiliar en su proyecto:

Swift2Objc_Helper.h

en el archivo de encabezado agregue este tipo de enumeración:

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

Puede haber otro lugar en su archivo .m para hacer un cambio: para incluir el archivo de encabezado oculto:

#import "[YourProjectName]-Swift.h"

reemplace [YourProjectName] con el nombre de su proyecto. Este archivo de encabezado expone todas las clases @objc definidas por Swift, enumeraciones a ObjC.

Puede recibir un mensaje de advertencia sobre la conversión implícita del tipo de enumeración ... Está bien.

Por cierto, podría usar este archivo auxiliar de encabezado para mantener algunos códigos ObjC como #define constantes.

David.Chu.ca
fuente
0

Si usted (como yo) realmente quiere utilizar las enumeraciones de String, puede crear una interfaz especializada para el objetivo-c. Por ejemplo:

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

Por supuesto, esto no le dará la conveniencia de autocompletar (a menos que defina constantes adicionales en el entorno del objetivo-c).

Lukas Kalinski
fuente
0

esto podría ayudar un poco más

Planteamiento del problema : - Tengo una enumeración en la clase rápida, a la que estoy accediendo desde otras clases rápidas, y ahora necesito acceder a ella desde mi clase C objetiva.

Antes de acceder desde la clase objetiva-c: -

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

Cambios para acceder desde la clase objetiva c

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

y agregue una función para pasarla al valor

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

Después de investigar esto, seguí encontrando solo respuestas parciales, así que creé un ejemplo completo de una aplicación Swift unida al Objetivo C que tiene enumeraciones Swift utilizadas por el código Objective C y enumeraciones Objective C utilizadas por el código Swift. Es un proyecto Xcode simple con el que puede ejecutar y experimentar. Fue escrito usando Xcode 10.3 con Swift 5.0

Proyecto de ejemplo

usuario3288724
fuente
No veo, donde su proyecto usa la enumeración rápida en el Objetivo C. Además, la definición de la enumeración rápida enum SwAnimalcarece de los principales@obj
oliolioli
0

En caso de que esté tratando de observar una enumeración que se ve así:

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

Esta solución me ayudó.

Clase observable:

  • crear @objc dynamic var observable: String?
  • cree su instancia de enumeración de esta manera:

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

Clase de observador:

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

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

De eso se trata. Ahora, cada vez que cambie el _enumNameen la clase observable, también se actualizará inmediatamente una instancia apropiada en la clase observador.

Por supuesto, esta es una implementación demasiado simplificada, pero debería darle una idea de cómo observar las propiedades incompatibles con KVO.

Gasper J.
fuente