Is it possible to use Swift's Enum in Obj-C?
Objective CEnumsSwiftObjective C Problem Overview
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
Objective C Solutions
Solution 1 - Objective C
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];
}
Solution 2 - Objective C
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
Solution 3 - Objective C
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.
Solution 4 - Objective C
Swift 4.1, Xcode 9.4.1:
-
Swift enum must be prefixed with
@objc
and beInt
type:// in .swift file: @objc enum CalendarPermission: Int { case authorized case denied case restricted case undetermined }
-
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"
Solution 5 - Objective C
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.
Solution 6 - Objective C
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).
Solution 7 - Objective C
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
}
Solution 8 - Objective C
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
Solution 9 - Objective C
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.