How to use Objective-C enum in Swift
I think this is a bug because Swift should define ==
for C enums or an "to Int" conversion but it doesn't.
The simplest workaround is redefining your C enum as:
typedef NS_ENUM(NSUInteger, JapaneseFoodType) {
JapaneseFoodType_Sushi = 1,
JapaneseFoodType_Tempura = 2,
};
which will allow LLVM to process the enum and convert it to a Swift enum (NS_ENUM
also improves your Obj-C code!).
Another option is to define the equality using reinterpret hack:
public func ==(lhs: JapaneseFoodType, rhs: JapaneseFoodType) -> Bool {
var leftValue: UInt32 = reinterpretCast(lhs)
var rightValue: UInt32 = reinterpretCast(rhs)
return (leftValue == rightValue)
}
Using non NS_ENUM objective-C enum in swift
The workaround to use .value to get the underlying integer doesn't work anymore as of Beta 4, as you said.
Unfortunately an enum
is not transferrable to Swift from Objective-C, it needs to be an NS_ENUM
.
I have the same setup as you in a project where I need the enum
from an Objective-C framework and use it in Swift.
The workaround I did was to create an Objective-C category that contains an NS_ENUM
and there I transfer the values from the framework enum
to my own NS_ENUM
.
Import the category in your bridging header and you should be able to use the enum
as you normally would do.
Something like this:
typedef NS_ENUM(NSUInteger, ConnectionStatus) {
ConnectionStatusIdle
}
- (ConnectionStatus)connectionStatus {
if [self getConnectionStatus] == WF_SENSOR_CONNECTION_STATUS_IDLE {
return ConnectionStatusIdle
}
}
Then you should be able to use it like this:
switch myObject.connectionStatus() {
case .Idle:
// do something
break
}
Objective-C enum in Swift
These get translated to
countDirection.Up
countDirection.Count
Swift removes as many letters as possible that the enum values have in common with the enumeration name. In your case, with an enumeration called countDirection and a value countDirectionUp, the whole "countDirection" is removed. It's not needed because you know which enum you are using, making your code considerable shorter.
Accessing NS_ENUM of objective-C in Swift
From Language Guide - Interoperability - Interacting with C APIs:
"The prefixes to C enumeration case names are removed when they are imported into Swift, whether they’re defined in system frameworks or
in custom code."
This means your first case in the ObserveType
enum have no name after being imported to Swift (which I'm somewhat surprised doesn't yield a compile error). If we were to print out the conversion, it would look something like (conceptually)
typedef NS_ENUM(NSInteger, ObserveType) {
Observe = 0
ObserveAll = 1
};
// imported like ...
enum ObserveType: Int {
case _ = 0 // obviously illegal if applied directly in Swift
case All
}
You could try to access the nameless case by using its rawValue
(0
), but I would recommend updating the name of the first case in your Obj-C enum, if possible.
if let empty = ObserveType(rawValue: 0) {
print(empty) // prints ""?
}
Is it possible to use Swift's Enum in Obj-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];
}
Different ways of declaring enum in Objective C
Is there any difference between the following or are they all the same?
There are differences, some due to C - which underlies Objective-C - and one if you are thinking about importing your Objective-C code into Swift.
Your first example:
enum WeekDays { Monday, ..., Friday };
is an original C enum
. This declares a type enum WeekDays
, with an underlying type of int
, and 5 literal values.
Now C is not a strongly typed language: the literal values here do not have type enum WeekDays
but rather are of type int
; and variables of type enum WeekDays
can be assigned values other than Monday
thru Friday
, and be assigned to int
variables without casts or conversions. The first literal value (Monday
here) will have the int
value 0
, and following ones will have a value one greater then the preceding literal (so here Friday
has the value 4
). Examples:
enum WeekDays one;
int two;
one = Monday;
two = Tuesday; // assigning enum literal to int is OK
two *= 42; // will produce an int value outside of Monday thru Friday
one = two; // which can be assigned to an enum WeekDays
one = 34; // int values can also be directly assigned
All the enum
variations are weak in this way. However many compilers, including those used by Xcode since at least v8, will issue warnings (not errors) in some cases, e.g. if a switch
expression is an enum
type and the case
labels either omit some of the declared literals or have values outside the declared values.
Giving the literals explicit values
Rather than relying on the default values specific values can be given to enum
literals. For example to give Monday
the value 1
through to Friday
having the value 5
:
enum WeekDays { Monday = 1, ..., Friday };
Literals without explicit values are assigned one more than the preceding literal as usual. The values do not need to be contiguous either:
enum WeekDays { Monday = 1, Tuesday = 42, Wednesday = 3, Thursday, Friday };
Using a typedef
Many C type declarations are complex and hard to parse (they are the stuff ion quiz questions), the C typedef
allows an alias for a particular type to be declared. A typedef
is often used with an enum
declaration to avoid having to use enum
when using the type. For example:
typedef enum WeekDays { Monday, ..., Friday } WeekDays;
declares the alias WeekDays
to mean enum WeekDays
. For example:
WeekDays one; // means exactly the same as the previous
// declaration for one
enum WeekDays one; // also valid and means the same thing
Seeing WeekDays
twice in the above declaration might be confusing, or simply too much typing for some people, and it can be omitted:
typedef enum { Monday, ..., Friday } WeekDays;
This is slightly different than the previous declaration, WeekDays
is now an alias for an anonymous enum
. With such a type the first form of declaration is now invalid:
enum Weekdays one; // invalid, no such enum
WeekDays one; // valid
Changing the underlying type
By default the underlying type of an enum
is int
. A different integral type can be specified, the type must be large enough to hold all the values the literals represent. The integral types are the integer, unsigned integer and character types. The underlying type is specified by adding : <type>
after the enum
tag, and the literals can be given specific values of the same type. For example:
typedef enum Vowels : char { Letter_A = 'a', ..., Letter_U = 'u' } Vowels;
as above an anonymous enum may be used:
typedef enum : char { Letter_A = 'a', ..., Letter_U = 'u' } Vowels;
Using NS_ENUM
NS_ENUM
is an (Apple) Objective-C convenience macro which expands out to a typedef
and an enum
declaration. For example:
typedef NS_ENUM(NSInteger, WeekDays) { Monday, ..., Friday };
expands to:
typedef enum WeekDays : NSInteger WeekDays;
enum WeekDays : NSInteger { Monday, ..., Friday };
which avoiding the forward declaration is equivalent to:
typedef enum WeekDays : NSInteger { Monday, ..., Friday } WeekDays;
Using Xcode v8, at least, there are no differences in compiler checks and warnings between using NS_ENUM
and the above direct typedef
.
When NS_ENUM
makes a difference
If you are writing Objective-C which will be used by Swift then using NS_ENUM
does make a difference: an enum declared using NS_ENUM
will be imported as a Swift enum
; whereas one declared directly will be imported as a Swift struct
and a collection of global read-only computed properties, one per literal.
Why this difference exists is not explained in the current Apple documentation (Using Swift with Cocoa and Objective-C (Swift 4.0.3), available through iBooks)
Finally, back to your examples
The above should enable you to figure out the differences:
Default C
enum
, underlying type isint
, type is used asenum WeekDays
Aliased C
enum
, underlying type isNSUinteger
, type is used asWeekDays
NS_ENUM
generatedenum
, underlying type isNSInteger
, type can be referred to as eitherWeekDays
orenum WeekDays
This declares two distinct types and will probably produce warnings. The first is an anonymous
enum
without an alias so no variables can later be introduced with this type. The literals it introduces are of typeint
. The second is an alias forNSInteger
. On 64-bit systemsNSInteger
is 64-bits, whileint
is 32-bits, so assignments between the literal type (int
) and the "enum" type (WeekDays
) may produce warnings. Furtherswitch
statements will not be checked as with the previous three versions, as they are simply based onNSInteger
. This version looks like an incorrect attempt to emulateNS_ENUM
and should not be used (it is invalid as such, just doesn't do what it suggests).
Hopefully all that illuminates more than it confuses!
NS_ENUM in Swift class as a property
Objective-C has no Optional Value,
You can declare the optionsFromA as:
public class ClassA: NSObject {
public var optionsFromA: EnumOption = .A
}
NS_ENUM in Swift
You can do it like this (though it's not pretty):
parser.registerOption("verbose", shortcut: 118 /* Array("v".utf8)[0] */, requirement: GBValueFlags.Required.rawValue)
Comparing NSNumber property wrapping NS_ENUM in Swift without using rawValue
You could define an extension for the DataObject class that defines a getter to do the unwrapping for you.
extension DataObject {
var friendStatusEnum: FriendStatus {
return FriendStatus(rawValue: friendStatus.integerValue)!
}
}
Note that it implicitly unwraps the enum, which means if for some reason the NSNumber has a value that doesn't match the enum it will crash. A more robust version would check for nil from the init and return a sensible default.
Related Topics
What Does the '@' Symbol Mean in Swift
Optional Field Type Doesn't Conform Protocol in Swift 3
Extending Collection with a Recursive Property/Method That Depends on the Element Type
What Does "Get" Mean in a Protocol's Property Declaration
Set a Default Value for Uipickerview in Swift
Storing Different Types of Value in Array in Swift
What's the Difference Between If Nil != Optional … and If Let _ = Optional …
Simultaneous Gesture Recognition for Specific Gestures
How to Implement Copy Constructor in Swift Subclass
Best Practice for Swift Methods That Can Return or Error
How to Send Data from iPhone to Watchkit in Swift
Parameters After Opening Bracket
Change Uibarbuttonitem from Uisearchbar
Remove All Non-Numeric Characters from a String in Swift
Prefer Large Titles and Refreshcontrol Not Working Well
Difference Between Using Objectidentifier() and '===' Operator