É 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

myLifeasdog
fonte
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];
}
Daniel Galasko
fonte
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
SirNod
fonte
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.

hpique
fonte
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"
leanne
fonte
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.

David.Chu.ca
fonte
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).

Lukas Kalinski
fonte
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
    }
Anurag Bhakuni
fonte
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

user3288724
fonte
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.

Gasper J.
fonte