É possível usar o Enum do Swift no Obj-C?


144

Estou tentando converter parte da minha classe Obj-C para Swift. E algumas outras classes de Obj-C ainda usam enum nessa classe convertida. Pesquisei nos Documentos de pré-lançamento e não consegui encontrá-lo ou talvez eu tenha perdido. Existe uma maneira de usar o Swift enum na classe Obj-C? Ou um link para o documento desta edição?

Foi assim que declarei minha enumeração no meu antigo código Obj-C e no novo código Swift.

meu antigo código Obj-C:

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

@interface SomeClass : NSObject

...

@end

meu novo código Swift:

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

class SomeClass: NSObject
{
    ...
}

Atualização: Das respostas. Não pode ser feito na versão Swift anterior à 1.2. Mas de acordo com este Blog Swift oficial . No Swift 1.2 lançado junto com o XCode 6.3, você pode usar o Swift Enum no Objective-C adicionando @objcna frente doenum


Não há realmente nenhuma necessidade de alterar seu código existente. Para interação entre Swift e Objective-C, assista aos vídeos da WWDC.
— gnasher729

Eu só quero verificar se meu projeto ainda funciona, se haverá uma classe rápida no meu projeto no futuro, mas não consigo descobrir qual classe devo adicionar para testá-lo. Então, eu converti o antigo. De qualquer forma, obrigado pela sua ajuda.
— myLifeasdog

Respostas:


226

A partir da versão 1.2 do Swift (Xcode 6.3), você pode. Prefixe simplesmente a declaração enum com@objc

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

Vergonhosamente retirado do Blog Swift

Nota: Isso não funcionaria para enumerações de String ou enumerações com valores associados. Seu enum precisará ser vinculado ao Int


No Objective-C, isso pareceria

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

8
muito obrigado por apontar isso ... note que no objetivo-c, embora os valores enum sejam chamados BearBlack, BearGrizzlye BearPolar!
— Nbk

1
Isso faz sentido não? Especialmente quando você olha como ele é traduzido do obj-c em rápida .. @nburk
— Daniel Galasko

1
Sim, isso funciona. No entanto, pelo menos no meu caso, um atributo "público" precisou ser adicionado à enumeração para ser acessível no lado Objective-C do projeto, assim: "@objc public enum Bear: Int"
— Pirkka Esko

Pena que não vejo nenhuma evidência de que os valores associados ao Swift enum sejam possíveis. pensamento positivo
— finneycanhelp

2
@AJit, por que você quer fazer isso? Basta adicionar o enum para seu próprio cabeçalho e de importação que no cabeçalho colmatar caso contrário é exclusiva para Swift
— Daniel Galasko

31

Para expandir a resposta selecionada ...

É possível compartilhar enumerações no estilo Swift entre Swift e Objective-C usando NS_ENUM().

Eles só precisam ser definidos em um contexto Objective-C usando NS_ENUM()e são disponibilizados usando a notação de ponto Swift.

Do Usando Swift com cacau e Objective-C

Swift importa como enumeração Swift qualquer enumeração de estilo C marcada com a NS_ENUMmacro. Isso significa que os prefixos para nomes de valores de enumeração são truncados quando são importados para o Swift, estejam eles definidos nas estruturas do sistema ou no código personalizado.

Objetivo-C

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

Rápido

let cellStyle: UITableViewCellStyle = .Default

Eu chego ao UITableViewCellStyle "a definição de função não é permitida aqui", o que estou fazendo de errado? Claro que tenho nomes diferentes, não UITableViewCellStyle.
— Cristi Băluță

1
Conforme observado na resposta do Sr. Galasko abaixo, o Swift 1.2 permite que enumerações sejam definidas no Swift e disponíveis no Obj-c. Esse estilo de definição, ou seja, NS_ENUM, ainda funciona no Obj-c, mas a partir do Swift versão 1.2 você pode usar qualquer uma das opções.
— 12139 SirNod

Descobri que há um problema com as enumerações de ObjC no Swift: elas não estão disponíveis. Em um fragmento como if let a = MyEnum(rawValue: 12345)onde 12345 não faz parte dessa enumeração, o resultado não é uma enumeração opcional, mas sim inválida.
— bio

30

No guia Usando Swift com cacau e Objective-C :

Uma classe ou protocolo Swift deve ser marcado com o atributo @objc para estar acessível e utilizável no Objective-C. [...]

Você terá acesso a qualquer coisa dentro de uma classe ou protocolo marcado com o atributo @objc, desde que seja compatível com o Objective-C. Isso exclui recursos apenas do Swift, como os listados aqui:

Tuplas / enumerações genéricas definidas em Swift / Estruturas definidas em funções Swift / de nível superior definidas em Swift / Variáveis ​​globais definidas em Swift / Tipealiases definidas em variáveis ​​do estilo Swift / Swift / Tipos aninhados / Funções com curry

Portanto, não, você não pode usar uma enumeração Swift em uma classe Objective-C.


2
Existe uma solução alternativa? Quero dizer, se eu criar uma classe Swift e eu absolutamente precisar de uma enumeração. Como posso tornar essa enum utilizável no Objective-C também?
— Raul Lopez

4
@RaulLopezVillalpando Se você sabe que interoperará com o Objective-C, declare a enumeração no Objective-C e permita que os dois idiomas o compartilhem.
— Gregory Higley

3
"Sim, criamos essa ponte para ajudá-lo a fazer a transição para o Swift, mas é inútil se você quiser usar algo legal, como Enums, Structs, Generics ... Então, existe isso ..."
— Kevin R

22
ESTA RESPOSTA NÃO É MAIS VÁLIDA !! desde o Xcode 6.3 / Swift 1.2, as enums do Swift também podem ser usadas no objetivo-c usando @objccomo @DanielGalasko apontado em sua resposta abaixo !!!
— Nbk

9
Apenas para esclarecer o comentário acima, citando o texto atual na documentação como no Swift 2.1 , "Enumerações definidas no Swift sem o tipo de valor bruto Int ". Portanto, se sua enumeração no Swift for declarada com um tipo de valor bruto Int, @obj enum MyEnum: Intela funcionará bem nos arquivos Objective-C, como mencionado anteriormente. Se a sua enumeração é declarada com outro tipo valor bruto como @obj enum MyOtherEnum: String, você não será capaz de usá-lo em arquivos Objective-C
— jjramos

7

Swift 4.1, Xcode 9.4.1:

1) O swift enum deve ter o prefixo @objce o Inttipo:

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

2) O nome do objetivo-C é o nome da enumeração + o nome do caso, por exemplo 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, é claro, lembre-se de importar o cabeçalho da ponte Swift como o último item na lista de importação do arquivo Objective-C:

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

por que MyApp-Swift deve ser o último?
— Paul T.

@PaulT. : provavelmente tem a ver com a ordem de processamento. Tente colocá-lo em outro lugar e você verá que não funcionará.
— leanne

Eu verifiquei, no meu projeto atual quase em todos os arquivos, está no final da seção de importação, mas em vários arquivos não está no final e o projeto funciona. pode estar em um novo Xcode funciona? Não posso verificá-lo agora, porque meu projeto atual leva anos para ser compilado :), mas vou ver mais tarde
— Paul T.

2

Se você preferir manter os códigos ObjC como estão, adicione um arquivo de cabeçalho auxiliar no seu projeto:

Swift2Objc_Helper.h

no arquivo de cabeçalho, adicione este tipo de enumeração:

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

Pode haver outro local no seu arquivo .m para fazer uma alteração: para incluir o arquivo de cabeçalho oculto:

#import "[YourProjectName]-Swift.h"

substitua [YourProjectName] pelo nome do seu projeto. Esse arquivo de cabeçalho expõe todas as classes @objc definidas pelo Swift, enumerações ao ObjC.

Você pode receber uma mensagem de aviso sobre conversão implícita do tipo de enumeração ... Está tudo bem.

A propósito, você pode usar esse arquivo auxiliar de cabeçalho para manter alguns códigos ObjC, como #define constantes.


0

Se você (como eu) realmente deseja fazer uso de enumerações de String, pode criar uma interface especializada para o objetivo-c. Por exemplo:

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

Obviamente, isso não lhe dará a conveniência do preenchimento automático (a menos que você defina constantes adicionais no ambiente objetivo-c).


0

isso pode ajudar um pouco mais

Declaração do problema : - Eu tenho enum na classe swift, que estou acessando de outras classes swift, e agora preciso acessá-lo na minha classe C objetiva.

Antes de acessá-lo da classe objetivo-c: -

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

Alterações para acessá-lo da classe objetivo c

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

e adicione uma função para passar o valor

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

0

Depois de pesquisar isso, continuei encontrando apenas respostas parciais, então criei um exemplo inteiro de um aplicativo Swift vinculado ao objetivo C que possui enumerações do Swift usadas pelo código do objetivo C e enumerações do objetivo C do código Swift. É um projeto simples do Xcode que você pode executar e experimentar. Foi escrito usando o Xcode 10.3 com Swift 5.0

Projeto de Exemplo


Eu não vejo, onde seu projeto usa o enum rápido no Objetivo C. Também a definição do enum rápido enum SwAnimalnão tem os principais@obj
— oliolioli

0

Caso você esteja tentando observar uma enumeração parecida com esta:

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

essa solução alternativa me ajudou.

Classe Observável:

  • crio @objc dynamic var observable: String?
  • crie sua instância enum assim:

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

Classe de observador:

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

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

Então é isso. Agora, toda vez que você alterar a _enumNameclasse observável, uma instância apropriada na classe observadora também será imediatamente atualizada.

Obviamente, essa é uma implementação simplificada, mas deve fornecer uma idéia de como observar propriedades incompatíveis com o KVO.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.