177

I'm trying to convert some of my Obj-C class to Swift. And some other Obj-C classes still using enum in that converted class. I searched In the Pre-Release Docs and couldn't find it or maybe I missed it. Is there a way to use Swift enum in Obj-C Class? Or a link to the doc of this issue?

This is how I declared my enum in my old Obj-C code and new Swift code.

my old Obj-C Code:

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

@interface SomeClass : NSObject

...

@end

my new Swift Code:

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

class SomeClass: NSObject
{
    ...
}

Update: From the answers. It can't be done in Swift older version than 1.2. But according to this official Swift Blog. In Swift 1.2 that released along with XCode 6.3, You can use Swift Enum in Objective-C by adding @objc in front of enum

myLifeasdog
  • 1,959
  • 2
  • 13
  • 11
  • There isn't really any need to change your existing code. For interaction between Swift and Objective-C, watch the WWDC videos. – gnasher729 Jun 10 '14 at 11:06
  • I just want to check if my project still work if there will be a swift class in my project in the future but I can't figure out what class should I add to test it. So, I convert the old one instead. Anyway, thanks for your help. – myLifeasdog Jun 10 '14 at 11:34

9 Answers9

278

As of Swift version 1.2 (Xcode 6.3) you can. Simply prefix the enum declaration with @objc

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

Shamelessly taken from the Swift Blog

Note: This would not work for String enums or enums with associated values. Your enum will need to be Int-bound


In Objective-C this would look like

Bear type = BearBlack;
switch (type) {
    case BearBlack:
    case BearGrizzly:
    case BearPolar:
       [self runLikeHell];
}
Daniel Galasko
  • 23,617
  • 8
  • 77
  • 97
  • 11
    thanks a lot for pointing it out... note that in objective-c though the enum values will be call `BearBlack`, `BearGrizzly` and `BearPolar`! – nburk Apr 23 '15 at 19:53
  • 1
    That makes sense no? Especially when you look at how it's translated from obj-c into swift.. @nburk – Daniel Galasko Apr 23 '15 at 20:32
  • 2
    Yes, this works. However, at least in my case a "public" attribute had to be added to the enumeration for it to be accessible on the Objective-C side of the project, like this: "@objc public enum Bear: Int" – Pirkka Esko Jun 30 '15 at 06:33
  • Too bad I don't see any evidence that Swift enum associated values are possible. *wishful thinking* – finneycanhelp Jul 03 '15 at 20:26
  • Is there any way to use enum in swift objective-c header?? not able to import "*-Swift.h" :( – AJit Dec 09 '15 at 17:16
  • 2
    @AJit why would you want to do that? Just add the enum to its own header and import that in the bridging header otherwise it's exclusive to Swift – Daniel Galasko Dec 09 '15 at 18:31
  • @DanielGalasko i have enum code in swift and i want to pass that enum instance to Objective-C++ init file, so need to pass through header file. BTW I am New with swift and Objective-c, so might be design problem Thanks for replay :) – AJit Dec 09 '15 at 18:39
  • @AJit maybe post that as a new question I don't know obj-c++ but my solution will make it available to any obj-c class provided you import the -Swift.h file – Daniel Galasko Dec 09 '15 at 18:41
  • Thanks @DanielGalasko, figured here to make enum in Objective-C instead of swift, thanks for the help! – AJit Dec 09 '15 at 19:28
  • 1
    This Solution doesn't work for String type enums in Swift. @objc on enums only works for Integer types. – Yash Bedi Sep 28 '18 at 13:55
  • I did this but am experience some issue in a .h file for undeclared identifier. I wonder if there is some weird circular imports or something – CDM social medias in bio Jun 13 '22 at 19:56
33

To expand on the selected answer...

It is possible to share Swift style enums between Swift and Objective-C using NS_ENUM().

They just need to be defined in an Objective-C context using NS_ENUM() and they are made available using Swift dot notation.

From the Using Swift with Cocoa and Objective-C

Swift imports as a Swift enumeration any C-style enumeration marked with the NS_ENUM macro. This means that the prefixes to enumeration value names are truncated when they are imported into Swift, whether they’re defined in system frameworks or in custom code.

Objective-C

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

Swift

let cellStyle: UITableViewCellStyle = .Default
Pang
  • 9,564
  • 146
  • 81
  • 122
SirNod
  • 781
  • 6
  • 10
  • I get at the UITableViewCellStyle "function definition is not allowed here", what am i doing wrong? Of course i have different namings not UITableViewCellStyle. – Cristi Băluță Nov 25 '14 at 15:16
  • 1
    As noted in Mr. Galasko's answer below, Swift 1.2 allows enums to be defined in Swift and available in Obj-c. This style of definition, namely NS_ENUM, still works in Obj-c, but as of Swift version 1.2 you have can use either option. – SirNod Mar 12 '15 at 20:17
  • I found there is a problem with ObjC enums in Swift: They are not failable. In a fragment like `if let a = MyEnum(rawValue: 12345)` where 12345 is not part of that enum, the result is not an optional but some invalid enum. – bio Sep 05 '17 at 13:11
  • Apple Doc: [Grouping Related Objective-C Constants](https://developer.apple.com/documentation/swift/objective-c_and_c_code_customization/grouping_related_objective-c_constants) – bshirley Apr 19 '22 at 19:38
29

From the Using Swift with Cocoa and Objective-C guide:

A Swift class or protocol must be marked with the @objc attribute to be accessible and usable in Objective-C. [...]

You’ll have access to anything within a class or protocol that’s marked with the @objc attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as those listed here:

Generics Tuples / Enumerations defined in Swift / Structures defined in Swift / Top-level functions defined in Swift / Global variables defined in Swift / Typealiases defined in Swift / Swift-style variadics / Nested types / Curried functions

So, no, you can't use a Swift enum in an Objective-C class.

hpique
  • 119,096
  • 131
  • 338
  • 476
  • 2
    Is there a workaround? I mean if i create a Swift class and I absolutely need an enum. How can I make that enum be usable into Objective-C as well? – Raul Lopez Oct 09 '14 at 16:51
  • source: https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html – fabb Oct 10 '14 at 07:40
  • 5
    @RaulLopezVillalpando If you know you're going to be interoperating with Objective-C, then you should declare the enumeration in Objective-C and let both languages share it. – Gregory Higley Nov 08 '14 at 00:16
  • 4
    "Yeah so we made this bridge to help you transition to Swift, but it's useless if you wanna use anything cool, like Enums, Structs, Generics... So there's that..." – Kevin R Mar 23 '15 at 22:20
  • 25
    THIS ANSWER IS NO LONGER VALID!! since Xcode 6.3 / Swift 1.2, Swift enums can also be used within objective-c using `@objc` as @DanielGalasko pointed out in his answer below!!! – nburk Apr 23 '15 at 19:52
  • 10
    Just to clarify the above comment, quoting the current text on the [documentation as of Swift 2.1](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html), "Enumerations defined in Swift **without Int raw value type**". So, if your enum in Swift is declared with an Int raw value type as in `@obj enum MyEnum: Int` it will work fine on Objective-C files as mentioned before. If your enum is declared with another raw value type like `@obj enum MyOtherEnum: String`, you will not be able to use it on Objective-C files – jjramos Mar 17 '16 at 21:02
16

Swift 4.1, Xcode 9.4.1:

1) Swift enum must be prefixed with @objc and be Int type:

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

2) Objective-C name is enum name + case name, eg 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;
    }
}

And, of course, remember to import your Swift bridging header as the last item in the Objective-C file's import list:

#import "MyAppViewController.h"
#import "MyApp-Swift.h"
leanne
  • 7,940
  • 48
  • 77
  • why should MyApp-Swift be the last? – Paul T. Feb 14 '20 at 12:33
  • @PaulT. : probably has to do with the order of processing. Try putting it elsewhere, and you’ll see it won’t work. – leanne Feb 14 '20 at 14:31
  • I checked, in my current project almost in all files it's at the end of import section, but in several files it's not at the end and project works. may be in a new Xcode it works? I can't check it now, because my current project takes ages to compile :), but I'm gonna check it later – Paul T. Feb 17 '20 at 06:25
2

If you prefer to keep ObjC codes as-they-are, you could add a helper header file in your project:

Swift2Objc_Helper.h

in the header file add this enum type:

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

There may be another place in your .m file to make a change: to include the hidden header file:

#import "[YourProjectName]-Swift.h"

replace [YourProjectName] with your project name. This header file expose all Swift defined @objc classes, enums to ObjC.

You may get a warning message about implicit conversion from enumeration type... It is OK.

By the way, you could use this header helper file to keep some ObjC codes such as #define constants.

David.Chu.ca
  • 37,408
  • 63
  • 148
  • 190
1

If you (like me) really want to make use of String enums, you could make a specialized interface for objective-c. For example:

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

Of course, this will not give you the convenience of auto-complete (unless you define additional constants in the objective-c environment).

Lukas Kalinski
  • 2,213
  • 24
  • 26
-1

After researching this, I kept finding only partial answers, so I created an entire example of a Swift App bridged to Objective C that has Swift enums used by Objective C code and Objective C enums used by Swift code. It is a simple Xcode project that you can run and experiment with. It was written using Xcode 10.3 with Swift 5.0

Example Project

user3288724
  • 87
  • 1
  • 2
  • I don't see, where your project uses the swift enum in Objective C. Also the definition of the swift enum `enum SwAnimal` lacks the leading `@obj` – oliolioli May 20 '20 at 10:42
-1

In case you are trying to observe an enum which looks like this:

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

this workaround helped me.

Observable Class:

  • create @objc dynamic var observable: String?
  • create your enum instance like this:

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

Observer Class:

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

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

Than's it. Now each time you change the _enumName in the observable class, an appropriate instance on the observer class will be immediately updated as well.

This is of course an oversimplified implementation, but it should give you an idea of how to observe KVO-incompatible properties.

Gasper J.
  • 481
  • 5
  • 11
-2

this might help a little more

Problem statement :- I have enum in swift class, which I am accessing form other swift classes, and Now I need to access it form my one of the objective C class.

Before accessing it from objective-c class :-

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

Changes for accessing it from objective c class

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

and add a function to pass it on the value

  @objc  func setNtc(view:NTCType)  {
        self.viewType = view; // assign value to the variable
    }
Anurag Bhakuni
  • 2,379
  • 26
  • 32