Using Non Ns_Enum Objective-C Enum in Swift

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:

  1. Default C enum, underlying type is int, type is used as enum WeekDays

  2. Aliased C enum, underlying type is NSUinteger, type is used as WeekDays

  3. NS_ENUM generated enum, underlying type is NSInteger, type can be referred to as either WeekDays or enum WeekDays

  4. 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 type int. The second is an alias for NSInteger. On 64-bit systems NSInteger is 64-bits, while int is 32-bits, so assignments between the literal type (int) and the "enum" type (WeekDays) may produce warnings. Further switch statements will not be checked as with the previous three versions, as they are simply based on NSInteger. This version looks like an incorrect attempt to emulate NS_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



Leave a reply



Submit